Compare commits

..

1 Commits

Author SHA1 Message Date
bherbruck f3c1d51c85 boolean: a grazing edge-by-face vertex at its three faces' common point; certify the continued edge (#3062)
Rebased onto main (its net change from 9b559c4c07, three-way per file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:03:51 -05:00
978 changed files with 17416 additions and 62177 deletions
+2 -28
View File
@@ -48,16 +48,9 @@ filter = "binary(action_matrix) & test(=action_matrix_sample)"
threads-required = 12
priority = 100
# The longest test by far (a median of 950 s on the 32 vCPU runner, #14362) starts at once, beside
# the action matrix sample. In the list below it would wait behind the tests that sort before it,
# and the run ends when it does.
[[profile.ci.overrides]]
filter = "package(solidcraft-kernel) & test(=thread_tests::a_long_thread_cuts_without_a_deep_tree)"
priority = 100
# The slowest tests start first, so a shard does not end with one of them running alone on a
# core while the others sit idle. Medians from the CI test timings (the junit artifacts), slowest
# first; a test over ~100 s belongs here (the medians of 24 full runs added the last ones, #14362).
# first; a test over ~100 s belongs here.
[[profile.ci.overrides]]
filter = """
(package(solidcraft-engine) & (
@@ -69,11 +62,6 @@ filter = """
| test(=tests::flush_join_loft::a_flange_flush_with_the_end_of_a_bent_tapered_tube_joins)
| test(=cmd::sheet::tests::perforated_sheet_takes_a_thousand_round_holes)
| test(=boolean_regression_tests::joined_loft_frames_plan_their_display_at_every_quality)
| test(=tests::join_onto_a_finely_faceted_import)
| test(=tests::chord_and_variable_fillets)
| test(=cmd::joints::tests::motion_sweep::find_limits_sees_arms_meet_behind_pins_already_in_each_other)
| test(=thread_tests::a_multi_start_thread_takes_the_volume_of_one_start)
| test(=thread_tests::a_thread_reaches_a_flat_shoulder_at_every_angle_and_leaves_it_whole)
))
| (package(solidcraft-engine) & (binary(atomic_commands) | binary(step_export_regressions)))
| (package(solidcraft-kernel) & (
@@ -82,23 +70,9 @@ filter = """
| test(=tspline::tests::hostile_tsplines_never_panic)
| test(=fill::tests::regular_rims_of_three_to_eight_sides_fill_with_one_face_and_close_the_cup)
| test(/^issue_788_tests::equal_bores_crossing_/)
| test(=blend_variable::tests::variable_radius_on_a_box_edge)
| test(=tests::measure_of_a_body_with_many_faces)
| test(=modify_history_tests::fillet_variable_and_chord)
| test(=sweep_rails_tests::a_parallel_rail_along_a_curved_path_keeps_the_section)
| test(=corner_g2::tests::a_box_with_every_edge_rounded_has_eight_g2_corners)
| test(=corner_g2::tests::a_long_setback_keeps_the_g2_patch_inside_the_box)
| test(=blend_corner::tests::issue1557_connected_rounds_keep_their_radii)
))
| (package(solidcraft-cli) & binary(naming_corpus) & test(=corpus_designs_name_alike_every_build_and_fail_where_a_reference_is_gone))
| (package(solidcraft-ui-egui) & (
test(=render_workspace::tests::progressive_image_controls_route_to_the_registered_host)
| test(=preselect_tests::variable_fillet_round_trip)
| test(=dialogs::dense::tests::a_saved_smooth_patch_reopens_with_its_setback)
| test(=dialogs::dense::tests::no_reachable_fillet_option_state_is_refused_for_its_options)
))
"""
priority = 99
priority = 100
# Each nextest test has its own process/device. Concurrent cold lavapipe path
# compiles contend for CPU and can exhaust the 600 s pipeline setup budget.
+1 -21
View File
@@ -430,11 +430,8 @@ jobs:
- name: Sorted lists
run: cargo xtask lists
# New UI text must reach every complete catalog; report it here, before review (#8542).
# Catalog coverage only: the command labels need the app's command table, which this job
# never builds (a release build of the CLI took 9-15 minutes). The `tests` job checks them
# against the CLI it builds anyway.
- name: Translations in the complete catalogs
run: cargo xtask i18n --check --no-registry
run: cargo xtask i18n --check
- name: Model decisions use exact geometry, not meshes
run: |
cargo xtask mesh-decisions
@@ -660,20 +657,6 @@ jobs:
--ignore-default-filter -E "($base) & not (package(=solidcraft-gpu) & test(/^path::/))" || status=$?
if [ "$status" -ne 0 ] && [ "$status" -ne 100 ]; then exit "$status"; fi
cargo xtask known-failing --junit "$junit"
# Every command label needs an English catalog entry (#8542). The label table is the CLI's
# command registry, so this builds the CLI in the profile the tests just used (the shared
# crates are cached) and reads it. Skipped when no selected package can change the table.
- name: Command labels in the translation catalogs
env:
FULL: ${{ needs.changes.outputs.full }}
PACKAGES: ${{ needs.changes.outputs.packages }}
run: |
case "$FULL $PACKAGES " in
true*|*" solidcraft-cli "*|*" solidcraft-ui-egui "*|*" xtask "*) ;;
*) echo "No package that feeds the command table changed."; exit 0 ;;
esac
cargo build -p solidcraft-cli --profile ci --locked
cargo xtask i18n --check --cli "${CARGO_TARGET_DIR:-target}/ci/solidcraft-cli"
- name: Compiler cache statistics
if: always()
run: if command -v sccache >/dev/null; then sccache --show-stats; else echo "sccache was not set up; built without it"; fi
@@ -1387,9 +1370,6 @@ jobs:
if: matrix.check == 'kernel rig and goldens'
env:
KERNEL_CASES_REPORT: ${{ github.workspace }}/solidcore/reports/kernel-rig/table.md
# each case in a process of its own, one per vCPU of the 16-vCPU, 64 GB runner, with a
# CPU-time hang limit (#14277)
KERNEL_CASES_JOBS: "16"
run: |
mkdir -p reports/kernel-rig
cd crates/solidcore-ops
+2 -3
View File
@@ -3,7 +3,7 @@
SolidCraft is a clean-room, pure-Rust parametric 3D CAD app (sketch solver, feature timeline, B-rep kernel, an egui UI that agents drive). This file is a router: the hard rules, then the skill to read for your task. Humans: CONTRIBUTING.md.
## Start here
Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelled `help wanted`, `good first issue`, `needs-triage`; architecture in `docs/architecture.md`.
Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelled `help wanted`, `good first issue`, `needs-triage`; architecture in `docs/architecture.md`. Local `plan/` notes are optional.
## Hard rules (what enforces each)
- Independent: never copy another product's code, icons, text or templates; never drive or take data from commercial CAD. `skills/solidcraft-ground-rules/SKILL.md`.
@@ -15,7 +15,7 @@ Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelle
- Layering; only `crates/kernel` uses truck; solidcore only via `solidcore-ops`/`-tess`/`-record` (`xtask/solidcore-seam.txt`): `cargo xtask layers`; see `docs/layers.md`.
- One outer UI container, one camera path (`navigation::handle`), colours from theme tokens: `cargo xtask ui-containers`.
- Application code is Rust only and builds for wasm: `cargo xtask wasm`, `cargo xtask web-offline-test`.
- The product name is SolidCraft; the old name lives in `docs/compatibility.md`.
- The product name is SolidCraft; the old name lives only in `docs/compatibility.md`.
- Sorted lists (message catalogs, `mod` lines, languages) stay sorted: `cargo xtask lists`. Never edit generated files (`docs/features.md`, `THIRD-PARTY-LICENSES.txt`) in a PR.
- A design-format change is ONE new file in `crates/doc/src/format/pending/`: `scripts/test-format-pending.sh`.
- A command has input and output schemas (will become required; `schema/unconverted.txt` only shrinks): `skills/solidcraft-commands/SKILL.md`.
@@ -37,7 +37,6 @@ Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelle
| A command, a crate boundary | `skills/solidcraft-commands/SKILL.md` |
| SolidCraft or solidcore, kernel, geometry | `skills/solidcraft-layers/SKILL.md` |
| A dialog, panel, camera, icon, colour | `skills/solidcraft-ui/SKILL.md` |
| Sheet metal | `skills/solidcraft-sheetmetal/SKILL.md` |
| Labels, messages, translations | `skills/solidcraft-ui-text/SKILL.md` |
| Saving something new in a design, import, export | `skills/solidcraft-file-formats/SKILL.md` |
| Preferences, a changed default | `skills/solidcraft-preferences/SKILL.md` |
+2
View File
@@ -706,6 +706,8 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| docs/design/preferences/figures/mouse-mapping.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-axes.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-axes.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-cube.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-cube.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-centre.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-centre.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-cursor.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
Generated
-13
View File
@@ -4216,15 +4216,6 @@ dependencies = [
"solidcore-record",
]
[[package]]
name = "solidcore-ops"
version = "0.1.0"
dependencies = [
"solidcore",
"solidcore-convert",
"solidcore-record",
]
[[package]]
name = "solidcore-record"
version = "0.1.0"
@@ -4407,7 +4398,6 @@ dependencies = [
"serde",
"serde_json",
"solidcore",
"solidcore-ops",
"solidcore-record",
"solidcore-tess",
"thiserror 2.0.21",
@@ -4475,7 +4465,6 @@ dependencies = [
"rayon",
"serde",
"serde_json",
"solidcore-ops",
"solidcore-record",
"solidcore-tess",
"solidcraft-geom",
@@ -4561,7 +4550,6 @@ dependencies = [
"log",
"serde_json",
"solidcore",
"solidcore-ops",
"solidcore-record",
"solidcraft-geom",
"solidcraft-profile",
@@ -4578,7 +4566,6 @@ dependencies = [
name = "solidcraft-step"
version = "0.40.0-rc.3"
dependencies = [
"solidcore-ops",
"solidcore-record",
"solidcraft-geom",
"solidcraft-profile",
-3
View File
@@ -50,9 +50,6 @@ solidcore = { path = "solidcore/crates/solidcore" }
# Geometry as data (solidcore's layers §1, "Record"): the B-rep record, its structural validation
# and the native body file. Vendored with solidcore, in the same subtree.
solidcore-record = { path = "solidcore/crates/solidcore-record" }
# The modelling layer (solidcore's layers §1, "Ops"): the record-level calls SolidCraft makes into the
# kernel, converting through solidcore-convert.
solidcore-ops = { path = "solidcore/crates/solidcore-ops" }
# Geometry made drawable (solidcore's layers §3): the one mesher, SolidCraft's, moved into the
# subtree (RFC 0003, item 1.1), with the display mesh and its levels of detail, the types
# SolidCraft's meshes are. Vendored with solidcore, in the same subtree.
+2 -3
View File
@@ -908,10 +908,9 @@ fn serve_mcp(
scope: Option<solidcraft_engine::io::vfs::PathScope>,
options: solidcraft_mcp::Options,
) -> Result<(), String> {
// Not the locked handles: the server reads stdin on a thread of its own (#14007).
let stdin = std::io::BufReader::new(std::io::stdin());
let stdin = std::io::stdin();
let stdout = std::io::stdout();
solidcraft_mcp::Server::new(backend).with_path_scope(scope).with_options(options).serve(stdin, stdout).map_err(|e| e.to_string())
solidcraft_mcp::Server::new(backend).with_path_scope(scope).with_options(options).serve(stdin.lock(), stdout.lock()).map_err(|e| e.to_string())
}
/// The port of the running desktop app: the one its discovery file names, if something listens
+5 -29
View File
@@ -191,9 +191,8 @@ mod web {
const CANVAS_ID: &str = "solidcraft_canvas";
const LOADING_ID: &str = "solidcraft_loading";
/// The viewport scene's depth buffer, a 32-bit float one (no stencil): WebGPU and WebGL2 both
/// have it, and the viewport draws it with reversed depth, whose precision follows the
/// distance from the eye (#1434). egui's own pass has none: the scene is drawn offscreen.
/// A 32-bit float depth buffer (no stencil): WebGPU and WebGL2 both have it, and the viewport
/// draws it with reversed depth, whose precision follows the distance from the eye (#1434).
const DEPTH_BITS: u8 = 32;
/// The loading animation (assets/styles/web/loading-logo.svg) settles into the finished mark
@@ -1211,25 +1210,6 @@ mod web {
storage.and_then(|s| s.get_item(&crate::channel::key(WEBGL_KEY)).ok().flatten()).is_some()
}
/// Install the GPU viewport the desktop's way: the scene is drawn offscreen with its own depth
/// buffer and the saved anti-aliasing, then copied into egui's pass, which has neither. Drawn
/// straight into egui's pass, the view was 1x whatever Graphics said (#11622).
///
/// The sample count follows the desktop's rule (`gpu::scene_samples`): the saved choice where
/// the browser's device draws it, else the supported default. WebGL draws 1x, as desktop
/// OpenGL does. eframe's web painter has no stencil buffer.
fn install_viewport(app: &mut SolveApp, rs: &eframe::egui_wgpu::RenderState) {
let backend = rs.adapter.get_info().backend;
let depth = eframe::egui_wgpu::depth_format_from_bits(DEPTH_BITS, 0);
let supported = eframe::egui_wgpu::supported_msaa_samples(&rs.adapter, &rs.device, rs.target_format, depth);
let requested = solidcraft_ui_egui::gpu::scene_samples(backend, app.preferences.msaa, &supported);
let drawn = app.set_wgpu_split(rs, DEPTH_BITS, 0, requested);
// After the install, which sets egui's own counts: those leave out the scene's depth
// buffer, and they include counts WebGL would draw at 1x.
app.msaa_supported = solidcraft_ui_egui::gpu::scene_sample_choices(backend, supported);
log::info!("SolidCraft graphics: {backend:?}, MSAA {drawn}x (saved {}x)", app.preferences.msaa);
}
/// Fetch font bytes asynchronously through the browser.
async fn fetch_font_bytes(url: &str) -> Result<Vec<u8>, String> {
let window = web_sys::window().ok_or("no window")?;
@@ -1246,9 +1226,6 @@ mod web {
pub fn start() {
eframe::WebLogger::init(log::LevelFilter::Info).ok();
solidcraft_ui_egui::i18n::install();
solidcraft_ui_egui::icon_svg::install();
solidcraft_ui_egui::workspace::install_tabs();
solidcraft_ui_egui::navigation_slots::install();
wasm_bindgen_futures::spawn_local(async {
let Some(window) = web_sys::window() else { return };
let launch = crate::Launch::parse(&query());
@@ -1262,9 +1239,7 @@ mod web {
log::error!("missing <canvas id=\"{CANVAS_ID}\">");
return;
};
// The window's pass (egui's) has no depth buffer: the scene has its own
// (`install_viewport`).
let mut options = eframe::WebOptions { depth_buffer: 0, ..Default::default() };
let mut options = eframe::WebOptions { depth_buffer: DEPTH_BITS, ..Default::default() };
if webgl()
&& let eframe::egui_wgpu::WgpuSetup::CreateNew(create) = &mut options.wgpu_options.wgpu_setup
{
@@ -1338,7 +1313,8 @@ mod web {
app.load_prefs(&p);
}
if let Some(rs) = &cc.wgpu_render_state {
install_viewport(&mut app, rs);
// eframe's web painter has no stencil buffer.
app.set_wgpu(rs, DEPTH_BITS, 0, 1);
}
if launch.open.is_none() && crate::query_flag(&query(), "sample") {
if let Err(e) = app.session.run_script(&solidcraft_engine::sample::script()) {
+11 -8
View File
@@ -848,10 +848,16 @@ fn backend_preference() -> Option<String> {
graphics().and_then(|v| v.get("backend").and_then(serde_json::Value::as_str).map(str::to_string))
}
/// The viewport scene's sample count, by the rule the web app shares
/// (`solidcraft_ui_egui::gpu::scene_samples`).
/// The viewport scene's sample count: the app's anti-aliasing (the window's pass is 1x), clamped
/// by the backend's policy (OpenGL renders 1x, see `effective_msaa_samples`). A count the device
/// cannot render with falls back to the supported default.
fn scene_samples(backend: eframe::wgpu::Backend, samples: u32, supported: &[u32]) -> u32 {
solidcraft_ui_egui::gpu::scene_samples(backend, samples, supported)
let requested = eframe::egui_wgpu::effective_msaa_samples(backend, samples.max(1));
if requested <= 1 || supported.is_empty() || supported.contains(&requested) {
requested
} else {
supported.iter().copied().filter(|&n| n <= solidcraft_ui_egui::prefs::Prefs::default().msaa).max().unwrap_or(1)
}
}
/// Keep the default until the installed renderer's startup check proves a fallback is needed.
@@ -934,9 +940,6 @@ fn main() -> eframe::Result {
objc2_foundation::NSProcessInfo::processInfo().setProcessName(objc2_foundation::ns_string!("SolidCraft"));
mark("main");
solidcraft_ui_egui::i18n::install();
solidcraft_ui_egui::icon_svg::install();
solidcraft_ui_egui::workspace::install_tabs();
solidcraft_ui_egui::navigation_slots::install();
// On OCLP-patched Macs, wgpu picks a Metal Shading Language standard that the system's
// compiler refuses (`invalid value 'metal3.2'`), because the patched OS reports a newer
// macOS version than the GPU's Metal compiler supports. Re-launching with
@@ -1631,7 +1634,7 @@ mod prefs_writer_tests {
let now = Instant::now();
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
assert_eq!(disk.flushes, 0, "the settings read at start are not written again");
app.preferences.navigator_style = NavigatorStyle::Custom;
app.preferences.navigator_style = NavigatorStyle::Cube;
app.preferences.display_quality = "fine".into();
assert!(writer.due(true, now), "a frame with input is checked");
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
@@ -1643,7 +1646,7 @@ mod prefs_writer_tests {
let mut next = new_app();
let stored = solidcraft_ui_egui::prefs::stored(|k| disk.flushed.get(k).cloned()).expect("settings on disk");
next.load_prefs(&stored);
assert_eq!(next.preferences.navigator_style, NavigatorStyle::Custom);
assert_eq!(next.preferences.navigator_style, NavigatorStyle::Cube);
assert_eq!(next.preferences.display_quality, "fine");
assert!(disk.flushed.contains_key(STORAGE_KEY));
}
+132 -6
View File
@@ -1,12 +1,135 @@
//! Navigation drawing definitions. Camera projection and picking remain in the UI widgets.
use egui::{Pos2, Shape, Stroke, pos2, vec2};
use egui::{Color32, FontId, Pos2, Rect, Shape, Stroke, pos2, vec2};
use solidcore_record::Vec3;
use solidcraft_engine::geom::Ring;
use solidcraft_theme::Tokens;
pub(crate) struct Facet {
pub(crate) direction: Vec3,
pub(crate) points: Ring<Pos2>,
pub(crate) outer_edges: Vec<bool>,
pub(crate) centre: Pos2,
pub(crate) label: String,
pub(crate) text_axes: Option<(egui::Vec2, egui::Vec2)>,
pub(crate) depth: f64,
}
// Private marker for label meshes with atlas-pixel UVs. The output hook replaces
// it with the font texture before any renderer sees the frame.
pub(crate) const LABEL_PIXELS: egui::TextureId = egui::TextureId::User(u64::from_le_bytes(*b"cubetext"));
struct LabelAtlas;
impl egui::plugin::Plugin for LabelAtlas {
fn debug_name(&self) -> &'static str {
"navigation cube label atlas"
}
fn output_hook(&mut self, ctx: &egui::Context, output: &mut egui::FullOutput) {
let size = ctx.fonts(|f| f.font_image_size());
let normalize = vec2(1.0 / size[0].max(1) as f32, 1.0 / size[1].max(1) as f32);
for shape in &mut output.shapes {
if let Shape::Mesh(mesh) = &mut shape.shape
&& mesh.texture_id == LABEL_PIXELS
{
let mesh = std::sync::Arc::make_mut(mesh);
mesh.texture_id = egui::TextureId::default();
for v in &mut mesh.vertices {
v.uv = (v.uv.to_vec2() * normalize).to_pos2();
}
}
}
}
}
/// Warp the font mesh into the projected face, so labels turn with the model.
pub(crate) fn face_text(painter: &egui::Painter, face: &Facet, ink: Color32, font_size: f32) {
let Some((r, down)) = face.text_axes else { return };
let opacity = ((face.depth - 0.18) / 0.17).clamp(0.0, 1.0) as f32;
if opacity <= 0.0 {
return;
}
let ink = ink.gamma_multiply(opacity);
let galley = painter.layout_no_wrap(face.label.clone(), FontId::proportional(font_size), ink);
let centre = galley.rect.center();
// Keep atlas-pixel UVs until the frame is complete: another label or widget
// can grow the atlas after this mesh is created, invalidating early UVs.
painter.ctx().add_plugin(LabelAtlas);
let text = Shape::Text(egui::epaint::TextShape::new(Pos2::ZERO, galley, ink));
let atlas = painter.ctx().fonts(|f| f.font_image_size());
let primitives = painter.ctx().tessellate(vec![egui::epaint::ClippedShape::new(Rect::EVERYTHING, text)], painter.ctx().pixels_per_point());
for primitive in primitives {
if let egui::epaint::Primitive::Mesh(mut mesh) = primitive.primitive {
mesh.texture_id = LABEL_PIXELS;
for v in &mut mesh.vertices {
v.uv = pos2(v.uv.x * atlas[0] as f32, v.uv.y * atlas[1] as f32);
let local = v.pos - centre;
v.pos = face.centre + r * local.x + down * (local.y * 1.35);
}
painter.add(Shape::mesh(mesh));
}
}
}
pub(crate) fn paint_cube(painter: &egui::Painter, faces: &[Facet], hovered: Option<usize>, t: Tokens, labels: bool, scale: f32) {
// A shared, opaque triangle mesh has no antialiasing fringes between facets.
// Per-polygon fringes and miter joins overlap as a face becomes edge-on.
let mut fill_mesh = egui::epaint::Mesh::default();
let mut edges: Vec<(Pos2, Pos2, usize, bool)> = Vec::new();
let hovered_direction = hovered.and_then(|i| faces.get(i)).map(|f| f.direction);
for face in faces {
let base = t.cube_face;
let shade = (0.72 + 0.28 * face.depth.min(1.0)) as f32;
let highlighted = hovered_direction == Some(face.direction);
let fill = if highlighted {
t.cube_hover
} else {
Color32::from_rgb((f32::from(base.r()) * shade) as u8, (f32::from(base.g()) * shade) as u8, (f32::from(base.b()) * shade) as u8)
};
let centre = fill_mesh.vertices.len() as u32;
fill_mesh.colored_vertex(face.centre, fill);
for &p in &face.points {
fill_mesh.colored_vertex(p, fill);
}
for (j, (&a, &b)) in face.points.edges().enumerate() {
fill_mesh.add_triangle(centre, centre + 1 + j as u32, centre + 1 + ((j + 1) % face.points.len()) as u32);
// Coplanar picking regions have no visible seams. Only actual cube
// edges and the hovered target's boundary receive an outline.
let outer = face.outer_edges.get(j).copied().unwrap_or(false);
if !highlighted && !outer {
continue;
}
if let Some(edge) = edges
.iter_mut()
.find(|(p, q, _, _)| (p.distance_sq(a) < 1e-6 && q.distance_sq(b) < 1e-6) || (p.distance_sq(b) < 1e-6 && q.distance_sq(a) < 1e-6))
{
edge.2 += usize::from(highlighted);
edge.3 |= outer;
} else {
edges.push((a, b, usize::from(highlighted), outer));
}
}
}
painter.add(Shape::mesh(fill_mesh));
for (a, b, highlights, outer) in edges {
// Two highlighted coplanar patches share an internal subdivision, not
// a target boundary. Actual cube edges remain visible across faces.
if !outer && highlights != 1 {
continue;
}
let highlighted = highlights > 0;
painter.line_segment([a, b], Stroke::new(1.0, if highlighted { t.accent } else { t.cube_border }));
}
if labels {
for face in faces {
face_text(painter, face, t.cube_text, t.font_heading * scale);
}
}
}
pub(crate) fn arrow(painter: &egui::Painter, at: Pos2, direction: egui::Vec2, hover: bool, t: Tokens) {
let side = vec2(-direction.y, direction.x);
painter.add(Shape::convex_polygon(
vec![at + direction * 7.0, at - direction * 5.0 + side * 7.0, at - direction * 5.0 - side * 7.0],
if hover { t.accent_soft } else { t.navigator_face },
Stroke::new(1.0, if hover { t.accent } else { t.navigator_border }),
if hover { t.accent_soft } else { t.cube_face },
Stroke::new(1.0, if hover { t.accent } else { t.cube_border }),
));
}
pub(crate) fn curved_arrow(painter: &egui::Painter, at: Pos2, clockwise: bool, hover: bool, t: Tokens, scale: f32) {
@@ -18,8 +141,8 @@ pub(crate) fn curved_arrow(painter: &egui::Painter, at: Pos2, clockwise: bool, h
at + vec2(angle.cos(), angle.sin()) * (32.0 * scale)
})
.collect();
painter.add(Shape::line(points.clone(), Stroke::new(5.0 * scale, if hover { t.accent } else { t.navigator_border })));
painter.add(Shape::line(points.clone(), Stroke::new(3.0 * scale, if hover { t.accent_soft } else { t.navigator_face })));
painter.add(Shape::line(points.clone(), Stroke::new(5.0 * scale, if hover { t.accent } else { t.cube_border })));
painter.add(Shape::line(points.clone(), Stroke::new(3.0 * scale, if hover { t.accent_soft } else { t.cube_face })));
if let Some(tip) = points.last() {
let sign = if clockwise { 1.0 } else { -1.0 };
arrow(painter, *tip, vec2(-end.sin(), end.cos()) * (sign * scale), hover, t);
@@ -27,8 +150,11 @@ pub(crate) fn curved_arrow(painter: &egui::Painter, at: Pos2, clockwise: bool, h
}
/// The pointer target around a compass end: larger than the drawn disc, so it is easy to hit.
pub(crate) const AXIS_RADIUS: f32 = 15.0;
pub(crate) fn axis_tip(painter: &egui::Painter, c: Pos2, name: &str, d: [f64; 3], at: Pos2, depth: f64, hovered: bool, t: Tokens) {
axis_tip_scaled(painter, c, name, d, at, depth, hovered, t, 1.0);
}
/// A compass axis end at a uniform scale, including its lettering and strokes.
/// The same compass artwork at a uniform scale, including its lettering and strokes.
#[allow(clippy::too_many_arguments)]
pub(crate) fn axis_tip_scaled(painter: &egui::Painter, c: Pos2, name: &str, d: [f64; 3], at: Pos2, depth: f64, hovered: bool, t: Tokens, scale: f32) {
let col = if d[0] != 0.0 {
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "إنشاء بلاغ…",
"Cross curves": "المنحنيات العرضية",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter يتابع في GitHub.",
"Cube": "مكعب",
"Current orthographic view (1:1 mm)": "العرض المتعامد الحالي (1:1 mm)",
"Current perspective view": "العرض المنظوري الحالي",
"Current plane": "المستوى الحالي",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "شكل SolidCraft وأماكن أجزائه.",
"prefs.interval_minutes": "{n} دقيقة",
"prefs.invert_curved_roll_arrows": "عكس سهمي التدوير المنحنيين",
"prefs.invert_curved_roll_arrows_note": "سهما التدوير المنحنيان عند زاوية أداة التنقل يدوران العرض داخل مستوى الشاشة. عند التشغيل: سهم التدوير مع عقارب الساعة يدور عكسها، وسهم العكس يدور معها. عند الإيقاف: يدور كل سهم بالعرض حسب انحنائه.",
"prefs.invert_navigator_arrows": "عكس أسهم تدوير أداة التنقل",
"prefs.invert_navigator_arrows_note": "تدوّر الأسهم المحيطة بأداة التنقل الكاميرا في الاتجاه الذي تشير إليه، كما في Fusion وInventor: السهم الموجود على اليسار يشير إلى اليمين ويدوّر الكاميرا إلى اليمين. عند الإيقاف: يدوّر السهم العرض نحو الجهة التي يقع فيها، فيدوّر السهم الأيسر الكاميرا إلى اليسار. لا يتأثر سهما الدوران المنحنيان.",
"prefs.invert_curved_roll_arrows_note": "سهما التدوير المنحنيان عند زاوية المكعب يدوران العرض داخل مستوى الشاشة. عند التشغيل: سهم التدوير مع عقارب الساعة يدور عكسها، وسهم العكس يدور معها. عند الإيقاف: يدور كل سهم بالعرض حسب انحنائه.",
"prefs.invert_navigator_arrows": "عكس أسهم تدوير مكعب العرض",
"prefs.invert_navigator_arrows_note": "تدوّر الأسهم المحيطة بالمكعب الكاميرا في الاتجاه الذي تشير إليه، كما في Fusion وInventor: السهم الموجود على اليسار يشير إلى اليمين ويدوّر الكاميرا إلى اليمين. عند الإيقاف: يدوّر السهم المكعب نحو الجهة التي يقع فيها، فيدوّر السهم الأيسر الكاميرا إلى اليسار. لا يتأثر سهما الدوران المنحنيان.",
"prefs.keep_unsaved_also_asks": "السؤال أيضًا عند إغلاق علامة التبويب",
"prefs.keep_unsaved_also_asks_tip": "عند إيقاف هذا الخيار، تُغلق علامة التبويب دون مربع حوار المتصفح بعد تحديث نسخة كل تصميم غير محفوظ.",
"prefs.keep_unsaved_in_browser": "الاحتفاظ بالعمل غير المحفوظ في هذا المتصفح",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "عند الإيقاف: لا يُميَّز أي شيء تحت المؤشر أثناء سحب مكوّن بأسهم أداة التحريك، فتبقى التجميعات الكبيرة سلسة. مع عرض مقطع أو تحليل يبقى التمييز كما هو، ولا يُميَّز شيء أبدًا عند سحب جزء على امتداد وصلاته.",
"prefs.navigation": "التنقل",
"prefs.navigation.axes_signed": "المحاور",
"prefs.navigation.cube_compact": "المكعب",
"prefs.navigation.device": "الجهاز",
"prefs.navigation.free": "حر",
"prefs.navigation.orbit_style": "نمط التدوير",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "طاولة دوارة",
"prefs.navigation_note": "كيف تحرك الفأرة ولوحة اللمس والفأرة ثلاثية الأبعاد العرض.",
"prefs.navigator_fit": "ملاءمة النموذج بعد تغيير العرض من متصفح العرض",
"prefs.navigator_fit_note": "النقر على وجه أو ركن أو سهم في أداة التنقل، أو على محور في أداة المحاور، يوجّه العرض أيضًا نحو منتصف النموذج من المسافة الواحدة التي تُظهره كاملًا من كل جهة (كرته المحيطة). يستخدم العرض الرئيسي التكبير والمركز ذاتهما ما دام هذا مفعّلًا، فلا تغيّر العروض المختارة بعده سوى الاتجاه. عند الإيقاف: يدور العرض في مكانه محتفظًا بالهدف والتكبير.",
"prefs.navigator_fit_note": "النقر على وجه أو ركن أو سهم في المكعب، أو على محور في أداة المحاور، يوجّه العرض أيضًا نحو منتصف النموذج من المسافة الواحدة التي تُظهره كاملًا من كل جهة (كرته المحيطة). يستخدم العرض الرئيسي التكبير والمركز ذاتهما ما دام هذا مفعّلًا، فلا تغيّر العروض المختارة بعده سوى الاتجاه. عند الإيقاف: يدور العرض في مكانه محتفظًا بالهدف والتكبير.",
"prefs.network_host_remove": "إزالة",
"prefs.network_locations": "السماح بمواقع الشبكة في التصاميم",
"prefs.network_locations_note": "للمؤسسات التي تحفظ التصاميم على خوادم الملفات. عند الإيقاف: الخوادم التي تسمح بها فقط.",
+1
View File
@@ -144,6 +144,7 @@
"Create Issue…": "Create Issue…",
"Cross curves": "Cross curves",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continues on GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Current orthographic view (1:1 mm)",
"Current perspective view": "Current perspective view",
"Current plane": "Current plane",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Prijavi problem…",
"Cross curves": "Presječne krive",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter nastavlja na GitHubu.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Trenutni ortografski prikaz (1:1 mm)",
"Current perspective view": "Trenutni perspektivni prikaz",
"Current plane": "Trenutna ravan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Kako SolidCraft izgleda i gdje su njegovi dijelovi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrni zakrivljene strelice za valjanje",
"prefs.invert_curved_roll_arrows_note": "Dvije zakrivljene strelice u uglu kocke valjaju prikaz unutar ravni ekrana. Uključeno: strelica u smjeru kazaljke na satu valja prikaz suprotno od smjera kazaljke na satu, a strelica suprotno od smjera kazaljke na satu valja ga u smjeru kazaljke na satu. Isključeno: svaka strelica valja prikaz onako kako je zakrivljena.",
"prefs.invert_navigator_arrows": "Obrni strelice za rotaciju kocke prikaza",
"prefs.invert_navigator_arrows_note": "Strelice oko kocke orbitiraju kameru u smjeru u kojem pokazuju, kao u programima Fusion i Inventor: strelica s lijeve strane pokazuje udesno i zakreće kameru udesno. Isključeno: strelica okreće kocku prema strani na kojoj se nalazi, pa lijeva strelica zakreće kameru ulijevo. Postavka ne utiče na zakrivljene strelice za valjanje.",
"prefs.keep_work_on_tab_switch": "Zadrži dijaloge i alate otvorenima pri prebacivanju između dizajna",
"prefs.keep_work_on_tab_switch_note": "Svaka kartica dizajna zadržava svoj otvoreni dijalog ili alat, s onim što ste u njemu izabrali i upisali, te svoju karticu trake s alatima. Kada se vratite na dizajn, ponovo su tu. Isključeno: prebacivanje između dizajna otkazuje ih i prikazuje karticu Model.",
"prefs.labels": "Oznake",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigacija",
"prefs.navigation_note": "Kako miš, trackpad i 3D miš pomjeraju prikaz.",
"prefs.navigator_fit": "Uklopi model nakon promjene prikaza u navigatoru",
"prefs.navigator_fit_note": "Lice, ugao ili strelica kocke prikaza, odnosno osa alata za orijentaciju, također usmjerava pogled na sredinu modela s jedne udaljenosti na kojoj se uklapa iz svakog smjera (njegova granična sfera). Početni prikaz koristi isti zum i centar dok je ova opcija uključena, pa se prikazi koje izaberete poslije njega samo okreću. Isključeno: prikaz se okreće na mjestu i zadržava svoj cilj i zum.",
"prefs.network_host_remove": "Ukloni",
"prefs.network_locations": "Dozvoli mrežne lokacije u dizajnima",
"prefs.network_locations_note": "Isključeno: povezane datoteke dizajna na drugom računaru (\\\\server\\share) otvaraju se samo sa servera navedenih ovdje ili nakon što ga dozvolite kada se to zatraži.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crear una incidència…",
"Cross curves": "Corbes transversals",
"Ctrl+Enter continues on GitHub.": "Ctrl+Retorn continua a GitHub.",
"Cube": "Cub",
"Current orthographic view (1:1 mm)": "Vista ortogràfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Pla actual",
@@ -2658,6 +2659,9 @@
"prefs.interface_note": "Com es veu SolidCraft i on se situen les seves parts.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertir les fletxes de gir corbes",
"prefs.invert_curved_roll_arrows_note": "Les dues fletxes corbes a la cantonada del cub giren la vista dins del pla de la pantalla. Activades: la fletxa horària gira en sentit antihorari i l'antihorària gira en sentit horari. Desactivades: cada fletxa gira la vista cap on es corba.",
"prefs.invert_navigator_arrows": "Invertir les fletxes de rotació del cub de vista",
"prefs.invert_navigator_arrows_note": "Les fletxes al voltant del cub orbiten la càmera cap on apunten, com a Fusion i Inventor: la fletxa de l'esquerra apunta a la dreta i gira la càmera a la dreta. Desactivades: una fletxa gira el cub cap al costat on és, així la fletxa de l'esquerra gira la càmera a l'esquerra. Les fletxes de gir corbes no en queden afectades.",
"prefs.keep_unsaved_also_asks": "Continuar preguntant quan es tanca la pestanya",
"prefs.keep_unsaved_also_asks_tip": "Amb això desactivat, la pestanya es tanca sense la finestra del navegador un cop la còpia de cada disseny sense desar està al dia.",
"prefs.keep_unsaved_in_browser": "Conservar la feina sense desar en aquest navegador",
@@ -2717,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Desactivat: mentre les fletxes de Moure arrosseguen un component, no es ressalta res del que hi ha sota el punter, cosa que manté àgils els ensamblatges grans. Amb una secció o una anàlisi mostrades, es ressalta igualment, i una peça arrossegada al llarg de les seves unions no ho ressalta mai.",
"prefs.navigation": "Navegació",
"prefs.navigation.axes_signed": "Eixos",
"prefs.navigation.cube_compact": "Cub",
"prefs.navigation.device": "Dispositiu",
"prefs.navigation.free": "Lliure",
"prefs.navigation.orbit_style": "Estil d'òrbita",
@@ -2724,6 +2729,7 @@
"prefs.navigation.turntable": "Plat giratori",
"prefs.navigation_note": "Com mouen la vista el ratolí, el panel tàctil i el ratolí 3D.",
"prefs.navigator_fit": "Ajustar el model després d'un canvi de vista del navegador",
"prefs.navigator_fit_note": "Una cara, cantonada o fletxa del cub de vista, o un eix del gizmo, també miren el centre del model des de la distància que l'ajusta des de tots els costats (la seva esfera envolupant). Inici fa servir el mateix zoom i centre mentre això està activat, així les vistes triades després només giren. Desactivat: la vista gira al seu lloc, mantenint el seu objectiu i zoom.",
"prefs.network_host_remove": "Eliminar",
"prefs.network_locations": "Permetre ubicacions de xarxa als dissenys",
"prefs.network_locations_note": "Per a organitzacions que desen dissenys en servidors de fitxers. Desactivat: només els servidors que permeteu.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Vytvořit hlášení…",
"Cross curves": "Příčné křivky",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter pokračuje na GitHubu.",
"Cube": "Krychle",
"Current orthographic view (1:1 mm)": "Aktuální pravoúhlý pohled (1:1 mm)",
"Current perspective view": "Aktuální perspektivní pohled",
"Current plane": "Aktuální rovina",
@@ -2658,6 +2659,9 @@
"prefs.interface_note": "Vzhled aplikace SolidCraft a rozmístění jejích částí.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrátit zakřivené šipky natočení",
"prefs.invert_curved_roll_arrows_note": "Dvě zakřivené šipky v rohu krychle natáčejí pohled v rovině obrazovky. Zapnuto: šipka po směru hodinových ručiček natáčí pohled proti směru hodinových ručiček a šipka proti směru hodinových ručiček ho natáčí po směru. Vypnuto: každá šipka natáčí pohled tak, jak je zakřivená.",
"prefs.invert_navigator_arrows": "Obrátit šipky otáčení krychle pohledu",
"prefs.invert_navigator_arrows_note": "Šipky kolem krychle otáčejí kameru tím směrem, kam míří, jako ve Fusion a Inventor: šipka vlevo míří doprava a stáčí kameru doprava. Vypnuto: šipka otáčí krychli na stranu, na které leží, takže šipka vlevo stáčí kameru doleva. Zakřivené šipky natočení tím nejsou dotčeny.",
"prefs.keep_unsaved_also_asks": "Přesto se ptát při zavření karty",
"prefs.keep_unsaved_also_asks_tip": "Když je vypnuto, karta se zavře bez dotazu prohlížeče, jakmile je kopie každého neuloženého návrhu aktuální.",
"prefs.keep_unsaved_in_browser": "Uchovávat neuloženou práci v tomto prohlížeči",
@@ -2717,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Vypnuto: když šipky Přesunout táhnou komponentu, nic pod ukazatelem se nezvýrazní, takže velké sestavy zůstanou plynulé. Při zobrazeném řezu nebo analýze se zvýrazňuje i tak a díl tažený po svých spojích nezvýrazňuje nikdy.",
"prefs.navigation": "Navigace",
"prefs.navigation.axes_signed": "Osy",
"prefs.navigation.cube_compact": "Krychle",
"prefs.navigation.device": "Zařízení",
"prefs.navigation.free": "Volné",
"prefs.navigation.orbit_style": "Styl otáčení",
@@ -2724,6 +2729,7 @@
"prefs.navigation.turntable": "Otočný stůl",
"prefs.navigation_note": "Jak myš, trackpad a 3D myš pohybují pohledem.",
"prefs.navigator_fit": "Přizpůsobit model po změně pohledu v navigátoru",
"prefs.navigator_fit_note": "Plocha, roh nebo šipka krychle pohledu, případně osa orientačního ovladače, také zaměří pohled na střed modelu z jediné vzdálenosti, ze které je celý vidět ze všech stran (jeho ohraničující koule). Domů při zapnutí používá stejné přiblížení a střed, takže pohledy zvolené po něm se jen otáčejí. Vypnuto: pohled se otáčí na místě a zachovává svůj cíl a přiblížení.",
"prefs.network_host_remove": "Odebrat",
"prefs.network_locations": "Povolit síťová umístění v návrzích",
"prefs.network_locations_note": "Vypnuto: propojené soubory návrhu na jiném počítači (\\\\server\\share) se otevírají jen ze zde uvedených serverů nebo poté, co jeden povolíte na výzvu.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Opret fejlrapport…",
"Cross curves": "Tværkurver",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsætter på GitHub.",
"Cube": "Terning",
"Current orthographic view (1:1 mm)": "Aktuel visning uden perspektiv (1:1 mm)",
"Current perspective view": "Aktuel perspektivvisning",
"Current plane": "Aktuelt plan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "SolidCrafts udseende og placeringen af dets dele.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Vend de buede rulningspile om",
"prefs.invert_curved_roll_arrows_note": "De to buede pile i kubens hjørne ruller visningen i skærmplanet. Slået til: Pilen med uret ruller mod uret, og pilen mod uret ruller med uret. Slået fra: Hver pil ruller visningen den vej, den krummer.",
"prefs.invert_navigator_arrows": "Vend visningskubens rotationspile om",
"prefs.invert_navigator_arrows_note": "Pilene rundt om kuben roterer kameraet i den retning, de peger, som i Fusion og Inventor: Pilen til venstre peger mod højre og svinger kameraet til højre. Slået fra: En pil drejer kuben mod den side, den sidder på, så venstre pil svinger kameraet til venstre. De buede rulningspile påvirkes ikke.",
"prefs.keep_work_on_tab_switch": "Behold dialoger og værktøjer åbne, når du skifter design",
"prefs.keep_work_on_tab_switch_note": "Hver designfane beholder sin åbne dialog eller sit åbne værktøj med det, du har valgt og skrevet i den, og sin fane på båndet. De er der igen, når du vender tilbage til designet. Slået fra: Skift af design annullerer dem og viser fanen Model.",
"prefs.labels": "Etiketter",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigation",
"prefs.navigation_note": "Hvordan musen, pegefeltet og 3D-musen styrer visningen.",
"prefs.navigator_fit": "Tilpas modellen efter et skift af visning i navigatoren",
"prefs.navigator_fit_note": "En flade, et hjørne eller en pil på visningskuben eller en akse på orienteringsgizmoen ser også mod modellens midte fra den ene afstand, der får den til at passe fra alle sider (dens omsluttende kugle). Hjem bruger samme zoom og centrum, mens dette er slået til, så visninger, der vælges bagefter, kun drejer. Slået fra: Visningen drejer på stedet og beholder sit mål og sin zoom.",
"prefs.network_host_remove": "Fjern",
"prefs.network_locations": "Tillad netværksplaceringer i designs",
"prefs.network_locations_note": "Slået fra: Et designs linkede filer på en anden computer (\\\\server\\share) åbnes kun fra de servere, der er angivet her, eller efter at du har tilladt en, når du bliver spurgt.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Issue erstellen…",
"Cross curves": "Querkurven",
"Ctrl+Enter continues on GitHub.": "Strg+Enter geht weiter zu GitHub.",
"Cube": "Würfel",
"Current orthographic view (1:1 mm)": "Aktuelle orthogonale Ansicht (1:1 mm)",
"Current perspective view": "Aktuelle perspektivische Ansicht",
"Current plane": "Aktuelle Ebene",
@@ -2468,6 +2469,8 @@
"prefs.interface_language": "Oberflächensprache",
"prefs.interface_note": "Legt das Erscheinungsbild von SolidCraft und die Anordnung seiner Bereiche fest.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_navigator_arrows": "Drehpfeile des Ansichtswürfels umkehren",
"prefs.invert_navigator_arrows_note": "Die Pfeile um den Würfel drehen die Kamera in die Richtung, in die sie zeigen, wie in Fusion und Inventor: Der linke Pfeil zeigt nach rechts und schwenkt die Kamera nach rechts. Aus: Ein Pfeil dreht den Würfel zu der Seite hin, an der er sitzt, sodass der linke Pfeil die Kamera nach links schwenkt. Die gebogenen Rollpfeile sind davon nicht betroffen.",
"prefs.keep_work_on_tab_switch": "Dialoge und Werkzeuge beim Wechsel zwischen Konstruktionen offen lassen",
"prefs.keep_work_on_tab_switch_note": "Jeder Konstruktions-Tab behält seinen offenen Dialog oder sein Werkzeug mit allem, was darin ausgewählt und eingegeben wurde, sowie seinen Werkzeugleisten-Tab. Beim Zurückkehren zur Konstruktion ist alles wieder da. Aus: Ein Wechsel bricht sie ab und zeigt den Tab Modell.",
"prefs.labels": "Beschriftungen",
@@ -2523,6 +2526,7 @@
"prefs.move_drag_highlights_tip": "Aus: Solange die Pfeile von Verschieben eine Komponente ziehen, wird nichts unter dem Zeiger hervorgehoben; so bleiben große Baugruppen flüssig. Mit einem Schnitt oder einer Analyse wird es trotzdem hervorgehoben, und ein entlang seiner Gelenke gezogenes Teil hebt nie etwas hervor.",
"prefs.navigation": "Navigation",
"prefs.navigation.axes_signed": "Achsen",
"prefs.navigation.cube_compact": "Würfel",
"prefs.navigation.device": "Gerät",
"prefs.navigation.free": "Frei",
"prefs.navigation.orbit_style": "Drehstil",
@@ -2530,6 +2534,7 @@
"prefs.navigation.turntable": "Drehteller",
"prefs.navigation_note": "Legt fest, wie Maus, Trackpad und 3D-Maus die Ansicht steuern.",
"prefs.navigator_fit": "Modell nach einem Ansichtswechsel am Navigator einpassen",
"prefs.navigator_fit_note": "Eine Fläche, Ecke oder ein Pfeil des Würfels oder eine Achse des Gizmos blickt auch auf die Mitte des Modells, aus dem einen Abstand, der es von jeder Seite einpasst (seine Hüllkugel). Home nutzt denselben Zoom und dieselbe Mitte, solange dies an ist, sodass danach gewählte Ansichten sich nur drehen. Aus: Die Ansicht dreht sich an Ort und Stelle und behält Ziel und Zoom.",
"prefs.network_host_remove": "Entfernen",
"prefs.network_locations": "Netzwerkspeicherorte in Designs zulassen",
"prefs.network_locations_note": "Für Organisationen, die Entwürfe auf Dateiservern speichern. Aus: nur erlaubte Server.",
+9 -9
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Create Issue…",
"Cross curves": "Cross curves",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continues on GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Current orthographic view (1:1 mm)",
"Current perspective view": "Current perspective view",
"Current plane": "Current plane",
@@ -1889,13 +1890,13 @@
"help.sketch.construction_line": "Create an infinite construction line through two points. Use it to lay out a sketch without splitting profiles.",
"help.sketch.construction_line.angle": "Create an infinite construction line at an angle from sketch X. Pick the point and type the angle, or pick its direction.",
"help.sketch.construction_line.bisector": "Pick two intersecting straight sketch lines, then choose either angle bisector. The result follows its source lines.",
"help.sketch.construction_line.horizontal": "Create an infinite horizontal construction line through a point, or type its distance from the sketch X axis. A typed distance becomes a driving dimension. Its horizontal constraint follows later edits.",
"help.sketch.construction_line.parallel": "Pick a straight sketch line, then place a parallel infinite construction line or type its offset. A typed offset becomes a driving distance. Right-click to choose another reference.",
"help.sketch.construction_line.horizontal": "Create an infinite horizontal construction line through a point. Its horizontal constraint follows later edits.",
"help.sketch.construction_line.parallel": "Pick a straight sketch line, then place a parallel infinite construction line. Right-click to choose another reference.",
"help.sketch.construction_line.perpendicular": "Pick a straight sketch line, then place a perpendicular infinite construction line. Right-click to choose another reference.",
"help.sketch.construction_line.tangent_at": "Create a tangent at a point on a circle or circular arc, or an endpoint of an open spline or conic. Pick the curve, then its contact point.",
"help.sketch.construction_line.tangent_external": "Pick a circle or circular arc, then an external point and a tangent solution. The previews show only contacts on the drawn arc.",
"help.sketch.construction_line.tangent_two": "Pick two circles or circular arcs, then choose a common tangent in the preview. Contacts must lie on the drawn curves.",
"help.sketch.construction_line.vertical": "Create an infinite vertical construction line through a point, or type its distance from the sketch Y axis. A typed distance becomes a driving dimension. Its vertical constraint follows later edits.",
"help.sketch.construction_line.vertical": "Create an infinite vertical construction line through a point. Its vertical constraint follows later edits.",
"help.sketch.copy": "Copies the selected sketch curves and points, together with the constraints and dimensions among them. Paste them into this sketch or another one.",
"help.sketch.create": "Starts a new 2D sketch on a plane or on a flat face of the model. Every extrude, revolve and sweep begins with a sketch.",
"help.sketch.cut": "Copies the selected sketch geometry and deletes it from the sketch, in one undo step. Paste it elsewhere in this sketch or into another one.",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "How SolidCraft looks and where its parts sit.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invert the curved roll arrows",
"prefs.invert_curved_roll_arrows_note": "The two curved arrows at the navigator's corner roll the view within the screen plane. On: the clockwise arrow rolls counterclockwise and the counterclockwise arrow rolls clockwise. Off: each arrow rolls the view the way it curls.",
"prefs.invert_navigator_arrows": "Invert the navigator rotation arrows",
"prefs.invert_navigator_arrows_note": "The arrows around the navigator orbit the camera the way they point, as in Fusion and Inventor: the arrow on the left points right and swings the camera right. Off: an arrow rotates the view toward the side it sits on, so the left arrow swings the camera left. The curved roll arrows are not affected.",
"prefs.invert_curved_roll_arrows_note": "The two curved arrows at the cube's corner roll the view within the screen plane. On: the clockwise arrow rolls counterclockwise and the counterclockwise arrow rolls clockwise. Off: each arrow rolls the view the way it curls.",
"prefs.invert_navigator_arrows": "Invert the view cube rotation arrows",
"prefs.invert_navigator_arrows_note": "The arrows around the cube orbit the camera the way they point, as in Fusion and Inventor: the arrow on the left points right and swings the camera right. Off: an arrow rotates the cube toward the side it sits on, so the left arrow swings the camera left. The curved roll arrows are not affected.",
"prefs.keep_unsaved_also_asks": "Still ask when the tab closes",
"prefs.keep_unsaved_also_asks_tip": "With this off, the tab closes without the browser's box once every unsaved design's copy is current.",
"prefs.keep_unsaved_in_browser": "Keep unsaved work in this browser",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Off: while Move's arrows drag a component, nothing under the pointer is highlighted, which keeps large assemblies smooth. With a section or an analysis shown it is highlighted all the same, and a part dragged along its joints never highlights it.",
"prefs.navigation": "Navigation",
"prefs.navigation.axes_signed": "Axes",
"prefs.navigation.cube_compact": "Cube",
"prefs.navigation.device": "Device",
"prefs.navigation.free": "Free",
"prefs.navigation.orbit_style": "Orbit style",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "Turntable",
"prefs.navigation_note": "How the mouse, trackpad and 3D mouse move the view.",
"prefs.navigator_fit": "Fit the model after a navigator view change",
"prefs.navigator_fit_note": "A face, corner or arrow of a navigator, or an axis of the gizmo, also looks at the middle of the model from the one distance that fits it from every side (its bounding sphere). Home uses the same zoom and centre while this is on, so views chosen after it only turn. Off: the view turns in place, keeping its target and zoom.",
"prefs.navigator_fit_note": "A face, corner or arrow of the view cube, or an axis of the gizmo, also looks at the middle of the model from the one distance that fits it from every side (its bounding sphere). Home uses the same zoom and centre while this is on, so views chosen after it only turn. Off: the view turns in place, keeping its target and zoom.",
"prefs.network_host_remove": "Remove",
"prefs.network_locations": "Allow network locations in designs",
"prefs.network_locations_note": "For organizations that keep designs on file servers. Off: only servers you allow.",
@@ -5298,14 +5300,12 @@
"ui.constraints_conflict": "Constraints conflict",
"ui.construction": "Construction",
"ui.construction.angle_hint": "Construction line: click a point, then type an angle or pick a direction",
"ui.construction.axis_hint": "Construction line: click a point, or type its distance from the sketch axis",
"ui.construction.bisector_hint": "Bisector: pick two intersecting straight lines, then the desired solution",
"ui.construction.common_hint": "Common tangent: pick two circles/arcs, then the desired solution",
"ui.construction.contact_hint": "Tangent: pick a circle/arc or open spline/conic, then the contact point (free-form curves: endpoints)",
"ui.construction.external_hint": "Tangent: pick a circle or arc, an external point, then the desired solution",
"ui.construction.free_hint": "Construction line: click two points; right-click to restart",
"ui.construction.normal_needs_length": "An infinite line is always construction: type a length to draw a normal line",
"ui.construction.parallel_hint": "Construction line: pick a straight line, then click or type the offset; right-click to change the reference",
"ui.construction.point_hint": "Construction line: click the point to pass through",
"ui.construction.reference_hint": "Construction line: pick a straight line, then a point; right-click to change the reference",
"ui.construction.ribbon_label": "X-Lines",
+7 -127
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crear incidencia…",
"Cross curves": "Curvas transversales",
"Ctrl+Enter continues on GitHub.": "Ctrl+Intro continúa en GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Plano actual",
@@ -264,7 +265,6 @@
"Edge": "Arista",
"Edges": "Aristas",
"Edit": "Editar",
"Edit Holes": "Editar agujeros",
"Edit Profile Sketch": "Editar boceto del perfil",
"Edit shortcuts": "Editar atajos",
"Enable rule": "Activar regla",
@@ -976,7 +976,6 @@
"browser.calibrate_click_a": "Haz clic en la imagen para el Punto A, o escribe sus coordenadas.",
"browser.calibrate_click_b": "Haz clic en la imagen para el Punto B, o escribe sus coordenadas.",
"browser.calibrate_title": "Calibrar: {name}",
"browser.canvas_locked": "El lienzo está bloqueado. Desbloquéalo primero.",
"browser.capture_many": "Se han movido {count} componentes, pero sus posiciones no se han capturado.",
"browser.capture_note": "Capturar posición conserva la nueva posición; Revertir posición restaura la anterior.",
"browser.capture_one": "Se ha movido un componente, pero su posición no se ha capturado.",
@@ -1206,7 +1205,6 @@
"cmd.material_properties_directional": "Módulo elástico direccional",
"cmd.material_properties_validate": "Validar datos del material físico",
"cmd.mesh_convert": "Convertir malla",
"cmd.model_body_features": "Listar operaciones del cuerpo",
"cmd.model_edges": "Listar aristas",
"cmd.model_faces": "Listar caras",
"cmd.model_threads": "Listar roscas",
@@ -1235,11 +1233,8 @@
"cmd.panel.dismiss": "Descartar vista previa de panel",
"cmd.panel.float": "Panel flotante",
"cmd.panel.focus": "Enfocar panel",
"cmd.panel.focus.next": "Enfocar el panel siguiente",
"cmd.panel.focus.previous": "Enfocar el panel anterior",
"cmd.panel.list": "Listar paneles",
"cmd.panel.move": "Mover panel",
"cmd.panel.move.next_zone": "Mover el panel a la zona siguiente",
"cmd.panel.native_close": "Volver a acoplar sección de panel nativo",
"cmd.panel.open": "Abrir panel",
"cmd.panel.peek": "Vista previa de panel colapsado",
@@ -1247,12 +1242,6 @@
"cmd.panel.reset_pair": "Restablecer divisor de panel",
"cmd.panel.resize": "Redimensionar sección de panel",
"cmd.panel.resize_pair": "Redimensionar divisor de panel",
"cmd.panel.sash.down": "Redimensionar el divisor del panel hacia abajo",
"cmd.panel.sash.left": "Redimensionar el divisor del panel hacia la izquierda",
"cmd.panel.sash.reset": "Restablecer el divisor del panel enfocado",
"cmd.panel.sash.right": "Redimensionar el divisor del panel hacia la derecha",
"cmd.panel.sash.up": "Redimensionar el divisor del panel hacia arriba",
"cmd.panel.toggle": "Alternar el panel enfocado",
"cmd.parameters_add": "Añadir parámetro de usuario",
"cmd.parameters_change": "Cambiar parámetros",
"cmd.parameters_comment": "Comentar parámetro",
@@ -1376,7 +1365,6 @@
"cmd.sketch.construction_line.tangent_external": "Tangente por punto externo",
"cmd.sketch.construction_line.tangent_two": "Tangente común",
"cmd.sketch.construction_line.vertical": "Línea de construcción vertical",
"cmd.sketch.replace": "Reemplazar boceto",
"cmd.sketch_arc3d": "Arco 3D",
"cmd.sketch_arc_center_point": "Arco de centro y punto",
"cmd.sketch_arc_tangent": "Arco tangente",
@@ -1508,7 +1496,6 @@
"cmd.timeline_stop": "Detener historial",
"cmd.timeline_suppress": "Suprimir operación",
"cmd.ui.assistant": "Alternar Asistente",
"cmd.ui.palette": "Buscar comandos",
"cmd.view.navigator": "Navegador de vistas personalizado",
"cmd.view.render_browser": "Explorador de render",
"cmd.view.render_dock": "Mover acople de render",
@@ -2028,7 +2015,6 @@
"help.view.visual_style": "Switches how the model is drawn: shaded with or without edges, wireframe, or with hidden edges. Use wireframe to see inside, shaded for a clean look.",
"history.sketch_under_constrained": "Bajo restricción ({count} grados de libertad)",
"history.sketch_under_constrained_one": "Bajo restricción ({count} grado de libertad)",
"hole_folder.applies_to": "Los cambios se aplican a los {count} agujeros de {folder}; cada uno conserva su posición.",
"hole_presets.confirm_delete": "Confirmar eliminación",
"hole_presets.delete": "Eliminar",
"hole_presets.delete_prompt": "Eliminar esta preconfiguración personal? Los agujeros existentes no cambian.",
@@ -2431,7 +2417,6 @@
"parts.dimension.width": "Anchura",
"parts.family.bearing": "Rodamiento rígido de bolas (envolvente)",
"parts.family.button_head_cap_screw": "Tornillo cabeza botón",
"parts.family.countersunk_socket_screw": "Tornillo avellanado con hexágono interior",
"parts.family.dowel_pin": "Pasador cilíndrico",
"parts.family.hex_bolt": "Tornillo de cabeza hexagonal",
"parts.family.hex_cap_screw_inch": "Tornillo de cabeza hexagonal (pulgadas)",
@@ -2530,8 +2515,6 @@
"prefs.bottom_centre": "Centro abajo",
"prefs.bottom_right": "Derecha abajo",
"prefs.browser": "Explorador",
"prefs.browser_body_features": "Operaciones bajo los cuerpos",
"prefs.browser_body_features_note": "Cada cuerpo del explorador se despliega sobre las operaciones de la línea de tiempo que lo construyeron, en el orden de la línea de tiempo.",
"prefs.browser_components_open": "Componentes abiertos al inicio",
"prefs.browser_components_open_note": "Cada componente del explorador empieza abierto, como antes, en lugar de cerrado hasta que lo abras.",
"prefs.browser_eye_left": "Ojo junto a la flecha de plegado",
@@ -2572,11 +2555,7 @@
"prefs.design_tools.degrees": "Grados",
"prefs.design_tools.double_click_help": "O para editar uno vinculado en su lugar.",
"prefs.design_tools.ghost": "Mostrar la posición anterior de las piezas movidas como un fantasma",
"prefs.design_tools.hole_group": "Agrupar agujeros creados juntos",
"prefs.design_tools.hole_group_help": "Los agujeros creados de una vez comparten una carpeta en el historial, cerrada al principio; ábrela para editar un agujero por separado.",
"prefs.design_tools.hole_moves_help": "Volver a seleccionar la cara mueve el agujero en lugar de eliminarlo.",
"prefs.design_tools.hole_several": "Varios agujeros en una cara",
"prefs.design_tools.hole_several_help": "Hacer clic en otro punto de una cara añade otro agujero; hacer clic en un agujero lo quita.",
"prefs.design_tools.hole_snaps_help": "El centro de una cara y los centros de sus aristas redondeadas.",
"prefs.design_tools.imported_files": "Archivos importados",
"prefs.design_tools.note": "Nota",
@@ -2658,8 +2637,6 @@
"prefs.history": "Historial",
"prefs.history_bar_groups": "Plegar la barra Historial en grupos",
"prefs.history_bar_groups_note": "En un historial largo, una serie de operaciones de un mismo componente se pliega en una ficha, y las carpetas de operaciones empiezan plegadas. Un ensamblaje STEP insertado va a una carpeta Grupo. Desactivado, se muestra cada operación, las carpetas empiezan abiertas y no se crea ninguna carpeta.",
"prefs.history_folder_kind_icon": "Icono de carpeta según sus operaciones",
"prefs.history_folder_kind_icon_note": "Una carpeta del historial cuyas operaciones son todas del mismo tipo muestra su icono.",
"prefs.history_group_joints": "Agrupar uniones en el Historial",
"prefs.history_group_joints_note": "Dos o más uniones se muestran como un botón con su número, y al hacer clic se muestra cada una. Desactivado, se muestra cada unión.",
"prefs.history_origin_bodies": "Mostrar origen y cuerpos al principio",
@@ -2682,6 +2659,9 @@
"prefs.interface_note": "Cómo se ve SolidCraft y dónde se sitúan sus partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertir las flechas de giro curvo",
"prefs.invert_curved_roll_arrows_note": "Las dos flechas curvas en la esquina del cubo giran la vista en el plano de la pantalla. Activado: la flecha horaria gira antihoraria y la antihoraria gira horaria. Desactivado: cada flecha gira la vista hacia donde se curva.",
"prefs.invert_navigator_arrows": "Invertir las flechas de rotación del cubo de vista",
"prefs.invert_navigator_arrows_note": "Las flechas alrededor del cubo orbitan la cámara hacia donde apuntan, como en Fusion e Inventor: la flecha de la izquierda apunta a la derecha y gira la cámara a la derecha. Desactivado: una flecha rota el cubo hacia el lado en que está, así la flecha izquierda gira la cámara a la izquierda. Las flechas de giro curvo no se ven afectadas.",
"prefs.keep_unsaved_also_asks": "Preguntar igualmente al cerrar la pestaña",
"prefs.keep_unsaved_also_asks_tip": "Con esto desactivado, la pestaña se cierra sin el cuadro del navegador en cuanto la copia de cada diseño sin guardar está al día.",
"prefs.keep_unsaved_in_browser": "Conservar el trabajo sin guardar en este navegador",
@@ -2741,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Desactivado: mientras las flechas de Mover arrastran un componente no se resalta nada bajo el puntero, y los ensamblajes grandes se mueven con fluidez. Con un corte o un análisis visible se resalta igualmente, y una pieza arrastrada a lo largo de sus uniones nunca lo resalta.",
"prefs.navigation": "Navegación",
"prefs.navigation.axes_signed": "Ejes",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Libre",
"prefs.navigation.orbit_style": "Estilo de órbita",
@@ -2748,6 +2729,7 @@
"prefs.navigation.turntable": "Plato giratorio",
"prefs.navigation_note": "Cómo mueven la vista el ratón, el panel táctil y el ratón 3D.",
"prefs.navigator_fit": "Ajustar el modelo tras un cambio de vista del navegador",
"prefs.navigator_fit_note": "Una cara, esquina o flecha del cubo de vista, o un eje del gizmo, también mira el centro del modelo desde la única distancia que lo encaja desde todos los lados (su esfera envolvente). Inicio usa el mismo zoom y centro mientras esto está activado, así que las vistas elegidas después solo giran. Desactivado: la vista gira en su lugar, manteniendo su objetivo y zoom.",
"prefs.network_host_remove": "Eliminar",
"prefs.network_locations": "Permitir ubicaciones de red en diseños",
"prefs.network_locations_note": "Desactivado: los archivos vinculados de un diseño en otro equipo (\\\\servidor\\\\carpeta) solo se abren desde los servidores listados aquí, o tras permitir uno cuando se pregunte.",
@@ -2760,7 +2742,6 @@
"prefs.origin_plane_names": "Nombres de los planos de origen",
"prefs.origin_plane_names_note": "Nombres que se muestran en el explorador, diálogos y listas. {top} es XY, {front} es XZ y {right} es YZ",
"prefs.overall_speed": "Velocidad general",
"prefs.panel_layout.recovery": "No se han podido restaurar las disposiciones de paneles guardadas. Los datos guardados se conservan; Clásico sigue disponible.",
"prefs.parameter_list_rows": "Filas de la lista de parámetros",
"prefs.parameter_list_rows_tip": "Número de filas visibles en la lista de parámetros",
"prefs.persistent_ribbon_pressed": "Resaltar comandos activos de la cinta",
@@ -2822,8 +2803,6 @@
"prefs.remember_dialog_values.help": "Desactivado de forma predeterminada. Si se activa, cuando un comando termina correctamente, sus valores y opciones seguros se reutilizan la próxima vez que abras el mismo comando, hasta que se cierre SolidCraft.",
"prefs.render_legacy_image_defaults": "Usar los valores de imagen anteriores de Render",
"prefs.render_legacy_image_defaults_help": "Mantiene el flujo manual anterior: las configuraciones nuevas usan rasterizado por CPU, el ray tracing por CPU conserva el muestreo fijo y los resultados renderizados se abren a mano. Al entrar en Render se reencuadra, se cambia de toma sin restaurar sus cámaras y se usa el encuadre y la navegación anteriores. Se desactiva la vista previa automática de la imagen en vivo. Las configuraciones guardadas no cambian.",
"prefs.render_legacy_memory_admission": "Usar las comprobaciones de memoria de renderizado anteriores",
"prefs.render_legacy_memory_admission_help": "Permite los renderizados nativos dentro de los presupuestos fijos de memoria compartida y del host aunque su estimación supere la RAM disponible. Los límites del dispositivo y las comprobaciones de asignación se siguen aplicando.",
"prefs.render_previous_geometry_budget": "Usar presupuesto de geometría previo de Render",
"prefs.render_previous_geometry_budget_help": "Restaurar el límite fijo previo (512 MiB en escritorio de 64 bits, 128 MiB en otros) en lugar del presupuesto basado en dispositivo.",
"prefs.reports_saved": "{n} guardados",
@@ -2850,8 +2829,6 @@
"prefs.select_other_hidden": "Seleccionar geometría oculta con Seleccionar otro",
"prefs.select_other_hidden_help": "Activado: incluir cuerpos, bocetos y aristas ocultas u ocluidas cerca del puntero. Desactivado: us",
"prefs.selecting": "Selección",
"prefs.shared_panel_layout": "Usar la disposición de paneles compartida",
"prefs.shared_panel_layout_help": "Muestra el explorador, el historial y el asistente existentes en paneles movibles. El cambio se aplica al aplicar las preferencias.",
"prefs.shift": "Mayús",
"prefs.shift_add_ctrl_toggle": "Mayús solo añade; Ctrl/Cmd alterna",
"prefs.shift_add_note": "Activado: Mayús añade y Ctrl/Cmd alterna. Desactivado (predeterminado): ambos alternan.",
@@ -2874,8 +2851,6 @@
"prefs.sketch.drawing": "Dibujo",
"prefs.sketch.ellipse_axes": "Dibujar elipses con sus ejes",
"prefs.sketch.ellipse_axes_note": "Los ejes mayor y menor como líneas de construcción, para poder acotar los semiejes y los ejes. Desactivado: solo la elipse, y al pulsar D sobre ella se da su radio menor allí donde se arrastre el valor, dibujado y etiquetado como R, como antes.",
"prefs.sketch.escape_twice_finishes": "Doble Esc finaliza el boceto",
"prefs.sketch.escape_twice_finishes_note": "Dos pulsaciones rápidas de Esc finalizan el boceto. Desactivado: Esc solo cancela la herramienta o la selección, y el boceto solo se finaliza con Finalizar boceto.",
"prefs.sketch.exit_keep": "Mantener",
"prefs.sketch.exit_previous": "Volver a la vista anterior",
"prefs.sketch.exit_unless_rotated": "Salvo que se haya girado",
@@ -3218,10 +3193,8 @@
"render.category_paint": "Pintura",
"render.category_plastic": "Plástico",
"render.category_wood": "Madera",
"render.caustics_area_lights": "Cáusticas de luces de área",
"render.caustics_depth": "Profundidad de trayectoria de cáusticas",
"render.caustics_enable": "Cáusticas de vidrio con luces puntuales y direccionales",
"render.caustics_environment": "Cáusticas del entorno",
"render.caustics_help": "El número de fotones controla el ruido y el trabajo. El radio de captación cambia detalle nítido por una estimación más suave. La CPU requiere iluminación indirecta.",
"render.caustics_path_required": "Las cáusticas por CPU requieren iluminación indirecta.",
"render.caustics_photons": "Fotones",
@@ -3398,7 +3371,7 @@
"render.cpu_opaque_required": "El trazado CPU requiere un fondo opaco. Desactiva Fondo transparente para continuar.",
"render.cpu_options_pending": "Este panel CPU todavía no puede editar emisión, efectos de superficie, vidrio ni anisotropía. Borra esas opciones de la API antes de usarlo.",
"render.cpu_path_depth": "Profundidad de trayectoria",
"render.cpu_path_help": "Añade rebotes de luz entre superficies opacas y a través de formas de vidrio admitidas. Requiere renderizado progresivo y sombras trazadas. La profundidad de trayectoria cuenta superficies sombreadas, límites de vidrio y eventos de dispersión, empezando por el primer impacto (1–64). La profundidad 1 da iluminación directa sobre superficies opacas; los valores mayores permiten más rebotes o cruces de vidrio y pueden tardar más. Desactiva la iluminación indirecta para usar reflexiones personalizadas o anisotropía.",
"render.cpu_path_help": "Añade rebotes de luz entre superficies opacas y a través de formas de vidrio admitidas. Requiere renderizado progresivo y sombras trazadas. La profundidad de trayectoria cuenta superficies sombreadas, límites de vidrio y eventos de dispersión, empezando por el primer impacto (1–16). La profundidad 1 da iluminación directa sobre superficies opacas; los valores mayores permiten más rebotes o cruces de vidrio y pueden tardar más. Desactiva la iluminación indirecta para usar reflexiones personalizadas o anisotropía.",
"render.cpu_path_lighting": "Iluminación indirecta",
"render.cpu_path_optics_reason": "Se conservan tus ajustes. Desactiva la iluminación indirecta para usar reflexiones personalizadas o anisotropía.",
"render.cpu_point": "Luz puntual",
@@ -3438,12 +3411,6 @@
"render.cpu_subsurface_denoise_reason": "La dispersión subsuperficial por CPU necesita la reducción de ruido desactivada. Se conservan tus ajustes.",
"render.cpu_subsurface_help": "La dispersión redirige la luz dentro del vidrio cerrado. Las tasas positivas necesitan iluminación indirecta con la reducción de ruido desactivada. La tasa es de colisiones por mm; 0 no añade dispersión. Un sesgo de fase positivo favorece las direcciones hacia delante; uno negativo, las hacia atrás.",
"render.cpu_summary": "Trazado CPU · reflejos · HDR · luces direccionales y puntuales",
"render.cpu_threads": "Procesos de CPU",
"render.cpu_threads_auto": "Automático",
"render.cpu_threads_custom": "Personalizado",
"render.cpu_threads_help": "Automático usa los procesos de CPU disponibles. Un proceso se ejecuta en serie. Más procesos pueden necesitar más memoria.",
"render.cpu_threads_single": "Uno",
"render.cpu_threads_web": "El renderizado en el navegador usa un proceso cooperativo. Se conserva la elección de procesos guardada para el escritorio.",
"render.cpu_transparent_help": "El PNG transparente quita el fondo y conserva la cobertura de los bordes. La opacidad del cuerpo y de la cara debe mantenerse al 100 %.",
"render.cpu_volume_enable_path": "Activar iluminación indirecta",
"render.cpu_volume_enable_path_plan": "Ray tracing en CPU · profundidad {depth} · {spp} muestras/píxel · semilla {seed} · sombras trazadas. Conserva la atmósfera definida y el presupuesto de imagen.",
@@ -3452,40 +3419,6 @@
"render.cpu_volume_method_incompatible": "Estos ajustes de luz, muestreo o atmósfera no se pueden transferir a este método. Se conservan tus ajustes.",
"render.cpu_volume_path_required": "Activa la iluminación indirecta para usar la atmósfera por CPU.",
"render.cpu_warm_cool": "Cálido y frío",
"render.denoise_class_background": "Omitido: fondo",
"render.denoise_class_coverage": "Omitido: cobertura parcial",
"render.denoise_class_degenerate": "Omitido: trayectoria degenerada",
"render.denoise_class_depth": "Omitido: límite de profundidad de trayectoria",
"render.denoise_class_emitter": "Omitido: emisor de luz",
"render.denoise_class_exit": "Omitido: salida incompatible",
"render.denoise_class_identity": "Omitido: límite de identidad de guía",
"render.denoise_class_lens": "Omitido: profundidad de campo",
"render.denoise_class_material": "Omitido: material no admitido",
"render.denoise_class_nested": "Omitido: medio anidado",
"render.denoise_class_optical": "Elegible: superficie refractada",
"render.denoise_class_reflection": "Omitido: punto final reflectante",
"render.denoise_class_surface": "Elegible: superficie",
"render.denoise_class_tir": "Omitido: reflexión total interna",
"render.denoise_class_transmission": "Omitido: transmisión adicional",
"render.denoise_class_unavailable": "Omitido: sin guía",
"render.denoise_class_volume": "Omitido: dispersión de volumen",
"render.denoise_diagnostics_counts": "Elegibles: {eligible} · Omitidos: {skipped}",
"render.denoise_diagnostics_enable": "Recopilar diagnóstico de reducción de ruido",
"render.denoise_diagnostics_grid": "Recuentos de píxeles con el tamaño interno {width} × {height}.",
"render.denoise_diagnostics_help": "Recopila los recuentos de píxeles elegibles y omitidos incluso con la reducción de ruido desactivada. Los recuentos usan el tamaño interno de renderizado; la máscara usa el tamaño de salida.",
"render.denoise_diagnostics_title": "Diagnóstico de reducción de ruido",
"render.denoise_export_mask": "Exportar máscara PNG",
"render.denoise_firefly": "Suprimir los píxeles brillantes aislados",
"render.denoise_format_mask": "Máscara PNG",
"render.denoise_mask_copy_help": "Exporta la máscara de reducción de ruido como PNG o vuelve a la imagen renderizada para copiarla.",
"render.denoise_mask_unavailable": "Activa el diagnóstico de reducción de ruido y renderiza una imagen para inspeccionar su máscara.",
"render.denoise_optical_filter": "Filtrar espejos y vidrio",
"render.denoise_optical_filter_help": "Filtra la luz reflejada y transmitida elegible. Desactívalo para reducir el ruido solo en superficies opacas.",
"render.denoise_passes": "Pasadas del filtro",
"render.denoise_settings_help": "Más pasadas suavizan un área mayor. La intensidad controla cuánto filtra cada pasada. Las trayectorias ópticas no admitidas no se filtran.",
"render.denoise_strength": "Intensidad de la reducción de ruido",
"render.denoise_view_image": "Imagen renderizada",
"render.denoise_view_mask": "Máscara de reducción de ruido",
"render.diag_bodies": "Cuerpos visibles",
"render.diag_job_details": "Detalles del trabajo capturado",
"render.diag_last_check": "Última comprobación",
@@ -4040,8 +3973,6 @@
"render.material_transient": "Ajustes ópticos temporales de esta pestaña. No se guardan en el diseño, la configuración de render ni la biblioteca de materiales.",
"render.material_v_up": "La coordenada V apunta hacia arriba en la imagen",
"render.material_weight": "Peso del recubrimiento (0–1)",
"render.metal_energy_compensation": "Recuperar la reflectancia del metal rugoso",
"render.metal_energy_compensation_help": "Compensa la luz perdida entre las microfacetas del metal rugoso. El renderizado por CPU necesita iluminación indirecta.",
"render.method_cpu": "Trazado CPU",
"render.method_gpu": "Trazado GPU",
"render.method_limit_raster": "Raster utiliza la vista opaca de estudio fija. Selecciona un método de trazado de rayos para los controles ópticos compatibles.",
@@ -4170,8 +4101,6 @@
"render.quality_denoise_on": "Reducción de ruido: Activada",
"render.quality_draft": "Boceto",
"render.quality_high": "Alto",
"render.quality_legacy_samples": "Valor guardado: {samples} spp. Las selecciones nuevas se limitan a {maximum} spp.",
"render.quality_preset_limit": "Este preajuste supera el límite de selección de 16384 spp. Elige un número de muestras de hasta 16384.",
"render.quality_projection_help": "Esta revisión solo cambia la resolución, el presupuesto de muestras, la profundidad de trayectoria, la semilla y la reducción de ruido. Los demás ajustes no cambian; el presupuesto no certifica la convergencia.",
"render.quality_review": "Revisar presupuesto de muestras",
"render.quality_summary": "{width} × {height} · {samples} muestras · profundidad {depth} · semilla {seed} · {denoise}",
@@ -4319,7 +4248,6 @@
"render.show_shots_label": "Mostrar tira de tomas",
"render.size_4k": "4K",
"render.size_4k_uhd": "4K UHD",
"render.size_8k_uhd": "8K UHD",
"render.size_custom": "Personalizado…",
"render.size_full_hd": "Full HD",
"render.size_hd": "HD",
@@ -4482,11 +4410,6 @@
"render.subsurface_enable": "Recorrido aleatorio de dispersión interna",
"render.subsurface_help": "Solo dieléctricos cerrados. Dispersión y absorción RGB son coeficientes separados por mm. Las trayectorias se dispersan dentro de la geometría y se refractan o reflejan en la frontera. Desactiva sombras rectas, reducción de ruido de superficies y volumen exterior; usa un estrato Fresnel. No es un filtro de difusión, rejilla de densidad ni material medido. Los medios densos pueden requerir más muestras y profundidad.",
"render.subsurface_rate": "Tasa de colisiones de dispersión",
"render.supersampling": "Supermuestreo",
"render.supersampling_dimensions": "Renderiza {width} × {height} y reduce a {output_width} × {output_height}. Usa el cuádruple de píxeles.",
"render.supersampling_help": "Renderiza al doble de ancho y alto y luego reduce en luz lineal. El tamaño de salida no cambia.",
"render.supersampling_off": "Desactivado",
"render.supersampling_x2": "2×",
"render.surface_import.author": "Autor",
"render.surface_import.busy": "Importando imagen…",
"render.surface_import.complete": "Elige una imagen e indica su autor, fuente y licencia.",
@@ -4500,8 +4423,6 @@
"render.surface_import.saved_cpu": "Guarda los mapas para usarlos con renderizado por CPU.",
"render.surface_import.source": "Fuente",
"render.surface_import.title": "Importar imagen",
"render.texture_filtering": "Filtrar el detalle de las texturas",
"render.texture_filtering_help": "Usa niveles mip y filtrado anisotrópico para reducir el aliasing de las texturas al reducirlas. Consume más memoria; desactivado mantiene el filtrado anterior.",
"render.tone_aces_fitted": "ACES ajustado",
"render.tone_reinhard": "Reinhard",
"render.transmission_scope": "El vidrio GPU admite medios separados certificados. No se admiten medios anidados sin restricciones ni un estimador de transmisión sin ruido.",
@@ -5596,7 +5517,6 @@
"ui.heading_plastic": "PLÁSTICO",
"ui.heading_position": "POSICIÓN",
"ui.heading_prepare": "PREPARAR",
"ui.heading_press_pull": "PULSAR/TIRAR",
"ui.heading_rectangular_pattern": "PATRÓN RECTANGULAR",
"ui.heading_revolve": "REVOLUCIÓN",
"ui.heading_right": "DERECHA",
@@ -5839,42 +5759,6 @@
"ui.panel_host.surface": "Panel",
"ui.panel_host.tab": "Pestaña del panel",
"ui.panel_host.tabs": "Todas las pestañas",
"ui.panel_layout.applied": "Se ha aplicado {name} a {workspace}",
"ui.panel_layout.cancel": "Cancelar",
"ui.panel_layout.confirm_replace": "¿Reemplazar «{name}»?",
"ui.panel_layout.copy": "Copiar",
"ui.panel_layout.current": "Disposición actual",
"ui.panel_layout.custom": "Personalizada",
"ui.panel_layout.custom_hint": "Se han movido paneles desde {name}.",
"ui.panel_layout.details": "Detalles",
"ui.panel_layout.layout_workspace": "Espacio de trabajo de disposición",
"ui.panel_layout.page_defaults_hint": "Restablece los ajustes de esta página. La organización de los paneles y las disposiciones guardadas se conservan.",
"ui.panel_layout.panel_layout": "Disposición de paneles",
"ui.panel_layout.panel_style": "Estilo de paneles",
"ui.panel_layout.replace": "Reemplazar disposición",
"ui.panel_layout.replace_current": "Reemplazar con la actual",
"ui.panel_layout.replace_short": "Reemplazar",
"ui.panel_layout.reset": "Restablecer espacio de trabajo",
"ui.panel_layout.reset_hint": "Restablece {workspace} a su disposición predeterminada. Las disposiciones guardadas se conservan.",
"ui.panel_layout.reset_short": "Restablecer",
"ui.panel_layout.restore_failed": "No se ha podido restaurar tu disposición",
"ui.panel_layout.save": "Guardar disposición",
"ui.panel_layout.save_as": "Guardar como",
"ui.panel_layout.save_as_tile": "Guardar como…",
"ui.panel_layout.selected": "seleccionada",
"ui.panel_layout.suggested_name": "Disposición {n}",
"ui.panel_layout.try_again": "Reintentar",
"ui.panel_layout.validation.builtin": "Las disposiciones integradas no se pueden cambiar",
"ui.panel_layout.validation.duplicate": "Ya tienes este nombre",
"ui.panel_layout.validation.empty": "Introduce un nombre",
"ui.panel_layout.validation.full": "64 de 64 guardadas. Elige una para reemplazarla.",
"ui.panel_layout.validation.invalid": "Usa de 1 a 64 caracteres, sin caracteres de control",
"ui.panel_layout.workspace.classic": "Clásico",
"ui.panel_layout.workspace.modelling": "Modelado",
"ui.panel_layout.workspace.render": "Renderizado",
"ui.panel_layout.workspace.review": "Revisión",
"ui.panel_layout.workspace.sketch": "Boceto",
"ui.panel_layout.your_layout": "tu disposición",
"ui.parallel": "Paralelo",
"ui.parameters": "Parámetros",
"ui.part_size_needs_a_part": "Seleccione una pieza normalizada insertada (un tornillo, una tuerca, una arandela o un pasador) para cambiar su tamaño. Para agrandar o reducir un cuerpo, use Escala.",
@@ -5940,8 +5824,6 @@
"ui.profiles": "Perfiles",
"ui.project": "Proyectar",
"ui.project_face_edges_sketch": "Proyectar aristas de caras en bocetos nuevos",
"ui.project_references_construction": "Proyectar referencias como geometría de construcción",
"ui.project_references_construction_note": "Proyectar, Intersecar, Incluir geometría 3D y las aristas de cara de un boceto nuevo sobre una cara crean geometría de construcción: referencias sobre las que dibujar, excluidas de los perfiles. Siguen vinculadas al modelo.",
"ui.properties": "Propiedades",
"ui.properties.copy_matrix": "Copiar matriz",
"ui.properties.first_moments": "Primeros momentos",
@@ -5985,8 +5867,6 @@
"ui.renderer": "Motor de renderizado",
"ui.repeat": "Repetir",
"ui.repeat_nothing": "Nada que repetir aún: inicia una herramienta o un diálogo primero.",
"ui.replace_sketch.from_file": "Desde un archivo de diseño…",
"ui.replace_sketch.no_sketches": "Ese diseño no tiene ningún boceto que reutilizar",
"ui.replace_with_link_done": "Las copias ya son colocaciones del diseño vinculado.",
"ui.report_a_bug": "Notificar un error",
"ui.report_characters_left_one": "Queda {count} carácter",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Luo ilmoitus…",
"Cross curves": "Poikkikäyrät",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter jatkaa GitHubissa.",
"Cube": "Kuutio",
"Current orthographic view (1:1 mm)": "Nykyinen ortografinen näkymä (1:1 mm)",
"Current perspective view": "Nykyinen perspektiivinäkymä",
"Current plane": "Nykyinen taso",
@@ -2680,6 +2681,9 @@
"prefs.interface_note": "Miltä SolidCraft näyttää ja missä sen osat sijaitsevat.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Käännä kaarevat kallistusnuolet",
"prefs.invert_curved_roll_arrows_note": "Kuution kulman kaksi kaarevaa nuolta kallistavat näkymää näytön tasossa. Päällä: myötäpäivään osoittava nuoli kallistaa vastapäivään ja vastapäivään osoittava myötäpäivään. Pois: kumpikin nuoli kallistaa näkymää kaartumissuuntaansa.",
"prefs.invert_navigator_arrows": "Käännä näkymäkuution kiertonuolet",
"prefs.invert_navigator_arrows_note": "Kuution ympärillä olevat nuolet kiertävät kameraa osoittamaansa suuntaan kuten Fusionissa ja Inventorissa: vasemmalla oleva nuoli osoittaa oikealle ja kääntää kameraa oikealle. Pois: nuoli kiertää kuutiota omaa puoltaan kohti, joten vasen nuoli kääntää kameraa vasemmalle. Kaarevat kallistusnuolet eivät muutu.",
"prefs.keep_unsaved_also_asks": "Kysy silti, kun välilehti suljetaan",
"prefs.keep_unsaved_also_asks_tip": "Kun tämä on pois päältä, välilehti sulkeutuu ilman selaimen kyselyikkunaa, kun jokaisen tallentamattoman mallin kopio on ajan tasalla.",
"prefs.keep_unsaved_in_browser": "Säilytä tallentamaton työ tässä selaimessa",
@@ -2739,6 +2743,7 @@
"prefs.move_drag_highlights_tip": "Pois: kun Siirrä-toiminnon nuolilla vedetään komponenttia, osoittimen alla olevaa kohdetta ei korosteta, mikä pitää suuret kokoonpanot sulavina. Kun leikkaus tai analyysi on näkyvissä, kohde korostetaan silti, eikä niveliään pitkin vedetty osa koskaan korosta sitä.",
"prefs.navigation": "Navigointi",
"prefs.navigation.axes_signed": "Akselit",
"prefs.navigation.cube_compact": "Kuutio",
"prefs.navigation.device": "Laite",
"prefs.navigation.free": "Vapaa",
"prefs.navigation.orbit_style": "Kiertotapa",
@@ -2746,6 +2751,7 @@
"prefs.navigation.turntable": "Pyörivä alusta",
"prefs.navigation_note": "Miten hiiri, kosketuslevy ja 3D-hiiri liikuttavat näkymää.",
"prefs.navigator_fit": "Sovita malli navigaattorin näkymänvaihdon jälkeen",
"prefs.navigator_fit_note": "Näkymäkuution pinta, kulma tai nuoli tai gizmon akseli katsoo myös mallin keskikohtaa siltä yhdeltä etäisyydeltä, joka sovittaa sen joka suunnasta (sen rajaava pallo). Aloitusnäkymä käyttää samaa zoomausta ja keskipistettä, kun tämä on päällä, joten sen jälkeen valitut näkymät vain kääntyvät. Pois: näkymä kääntyy paikallaan säilyttäen kohteensa ja zoomauksensa.",
"prefs.network_host_remove": "Poista",
"prefs.network_locations": "Salli verkkosijainnit malleissa",
"prefs.network_locations_note": "Pois: mallin linkitetyt tiedostot toisella tietokoneella (\\\\server\\share) avataan vain tässä luetelluilta palvelimilta tai sen jälkeen, kun sallit palvelimen kysyttäessä.",
+5 -4
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Créer un ticket…",
"Cross curves": "Courbes transversales",
"Ctrl+Enter continues on GitHub.": "Ctrl+Entrée continue sur GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Vue orthographique actuelle (1:1 mm)",
"Current perspective view": "Vue en perspective actuelle",
"Current plane": "Plan actuel",
@@ -2255,9 +2256,9 @@
"prefs.interface_note": "L'apparence de SolidCraft et la place de ses éléments.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverser les flèches courbes de roulis",
"prefs.invert_curved_roll_arrows_note": "Les deux flèches courbes au coin du navigateur font rouler la vue dans le plan de l'écran. Activé : la flèche horaire fait rouler dans le sens antihoraire et la flèche antihoraire dans le sens horaire. Désactivé : chaque flèche fait rouler la vue dans le sens de sa courbure.",
"prefs.invert_navigator_arrows": "Inverser les flèches de rotation du navigateur de vue",
"prefs.invert_navigator_arrows_note": "Les flèches autour du navigateur font orbiter la caméra dans le sens où elles pointent, comme dans Fusion et Inventor : la flèche de gauche pointe vers la droite et fait pivoter la caméra vers la droite. Désactivé : une flèche fait tourner la vue vers le côté où elle se trouve, donc la flèche de gauche fait pivoter la caméra vers la gauche. Les flèches courbes de roulis ne sont pas concernées.",
"prefs.invert_curved_roll_arrows_note": "Les deux flèches courbes au coin du cube font rouler la vue dans le plan de l'écran. Activé : la flèche horaire fait rouler dans le sens antihoraire et la flèche antihoraire dans le sens horaire. Désactivé : chaque flèche fait rouler la vue dans le sens de sa courbure.",
"prefs.invert_navigator_arrows": "Inverser les flèches de rotation du cube de vue",
"prefs.invert_navigator_arrows_note": "Les flèches autour du cube font orbiter la caméra dans le sens où elles pointent, comme dans Fusion et Inventor : la flèche de gauche pointe vers la droite et fait pivoter la caméra vers la droite. Désactivé : une flèche fait tourner le cube vers le côté où elle se trouve, donc la flèche de gauche fait pivoter la caméra vers la gauche. Les flèches courbes de roulis ne sont pas concernées.",
"prefs.keep_work_on_tab_switch": "Garder dialogues et outils ouverts en changeant de conception",
"prefs.keep_work_on_tab_switch_note": "Chaque onglet de conception garde son dialogue ou son outil ouvert, avec ce que vous y avez sélectionné et saisi, ainsi que son onglet de barre d'outils. Vous les retrouvez en revenant à la conception. Désactivé : changer de conception les annule et affiche l'onglet Modèle.",
"prefs.labels": "Libellés",
@@ -2296,7 +2297,7 @@
"prefs.navigation": "Navigation",
"prefs.navigation_note": "Comment la souris, le pavé tactile et la souris 3D déplacent la vue.",
"prefs.navigator_fit": "Cadrer le modèle après un changement de vue du repère de navigation",
"prefs.navigator_fit_note": "Une face, un coin ou une flèche du navigateur de vue, ou un axe du gizmo, regarde aussi le milieu du modèle depuis la distance unique qui le cadre sous tous les côtés (sa sphère englobante). Accueil utilise le même zoom et le même centre tant que cette option est activée, de sorte que les vues choisies ensuite ne font que tourner. Désactivé : la vue tourne sur place, en gardant sa cible et son zoom.",
"prefs.navigator_fit_note": "Une face, un coin ou une flèche du cube de vue, ou un axe du gizmo, regarde aussi le milieu du modèle depuis la distance unique qui le cadre sous tous les côtés (sa sphère englobante). Accueil utilise le même zoom et le même centre tant que cette option est activée, de sorte que les vues choisies ensuite ne font que tourner. Désactivé : la vue tourne sur place, en gardant sa cible et son zoom.",
"prefs.network_host_remove": "Retirer",
"prefs.network_locations": "Autoriser les emplacements réseau dans les conceptions",
"prefs.network_locations_note": "Désactivé : les fichiers liés d'une conception situés sur un autre ordinateur (\\\\server\\share) ne sont ouverts que depuis les serveurs listés ici, ou après en avoir autorisé un sur demande.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Crear incidencia…",
"Cross curves": "Curvas transversais",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continúa en GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Plano actual",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Como se ve SolidCraft e onde están as súas partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter as frechas curvas de balanceo",
"prefs.invert_curved_roll_arrows_note": "As dúas frechas curvas da esquina do cubo fan xirar a vista no plano da pantalla. Activado: a frecha en sentido horario xira en sentido antihorario e a frecha en sentido antihorario xira en sentido horario. Desactivado: cada frecha xira a vista no sentido en que se curva.",
"prefs.invert_navigator_arrows": "Invertir as frechas de rotación do cubo de vistas",
"prefs.invert_navigator_arrows_note": "As frechas arredor do cubo fan orbitar a cámara na dirección na que apuntan, como en Fusion e Inventor: a frecha da esquerda apunta á dereita e move a cámara cara á dereita. Desactivado: unha frecha xira o cubo cara ao lado no que está, así que a frecha da esquerda move a cámara cara á esquerda. As frechas curvas de balanceo non se ven afectadas.",
"prefs.keep_work_on_tab_switch": "Manter abertos os diálogos e as ferramentas ao cambiar de deseño",
"prefs.keep_work_on_tab_switch_note": "Cada lapela de deseño conserva o seu diálogo ou ferramenta aberto, co que escolliches e escribiches nel, e a súa lapela da barra de ferramentas. Volven estar aí cando regresas ao deseño. Desactivado: cambiar de deseño cancélaos e mostra a lapela Modelo.",
"prefs.labels": "Etiquetas",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navegación",
"prefs.navigation_note": "Como moven a vista o rato, o panel táctil e o rato 3D.",
"prefs.navigator_fit": "Axustar o modelo despois dun cambio de vista do navegador",
"prefs.navigator_fit_note": "Unha cara, esquina ou frecha do cubo de vistas, ou un eixe do gizmo, tamén mira ao centro do modelo desde a única distancia que o abarca por todos os lados (a súa esfera delimitadora). Inicio usa o mesmo zoom e centro mentres isto está activado, así que as vistas escollidas despois só xiran. Desactivado: a vista xira no sitio, conservando o seu punto de mira e o seu zoom.",
"prefs.network_host_remove": "Quitar",
"prefs.network_locations": "Permitir ubicacións de rede nos deseños",
"prefs.network_locations_note": "Desactivado: os ficheiros ligados dun deseño que están noutro ordenador (\\\\server\\share) só se abren desde os servidores listados aquí, ou despois de que permitas un cando se che pregunte.",
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "יצירת דיווח…",
"Cross curves": "עקומות חוצות",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter ממשיך ב־GitHub.",
"Cube": "קובייה",
"Current orthographic view (1:1 mm)": "התצוגה האורתוגרפית הנוכחית (1:1 mm)",
"Current perspective view": "תצוגת הפרספקטיבה הנוכחית",
"Current plane": "המישור הנוכחי",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "איך SolidCraft נראה והיכן חלקיו ממוקמים.",
"prefs.interval_minutes": "{n} דק׳",
"prefs.invert_curved_roll_arrows": "היפוך חצי הגלילה המעוגלים",
"prefs.invert_curved_roll_arrows_note": "שני החצים המעוגלים בפינת הנווט מסובבים את התצוגה במישור המסך. פועל: החץ עם כיוון השעון מסובב נגד כיוון השעון, והחץ נגד כיוון השעון מסובב עם כיוון השעון. כבוי: כל חץ מסובב את התצוגה לפי העקום שלו.",
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב הנווט",
"prefs.invert_navigator_arrows_note": "החצים סביב הנווט מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את התצוגה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
"prefs.invert_curved_roll_arrows_note": "שני החצים המעוגלים בפינת הקובייה מסובבים את התצוגה במישור המסך. פועל: החץ עם כיוון השעון מסובב נגד כיוון השעון, והחץ נגד כיוון השעון מסובב עם כיוון השעון. כבוי: כל חץ מסובב את התצוגה לפי העקום שלו.",
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב קוביית התצוגה",
"prefs.invert_navigator_arrows_note": "החצים סביב הקובייה מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את הקובייה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
"prefs.keep_unsaved_also_asks": "לשאול גם כשהכרטיסייה נסגרת",
"prefs.keep_unsaved_also_asks_tip": "כשאפשרות זו כבויה, הכרטיסייה נסגרת ללא חלון הדפדפן לאחר שהעותק של כל תכן שלא נשמר עודכן.",
"prefs.keep_unsaved_in_browser": "לשמור עבודה שלא נשמרה בדפדפן זה",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "כבוי: בזמן שחצי ההזזה גוררים רכיב, דבר אינו מודגש מתחת לסמן, וכך מכלולים גדולים נשארים חלקים. כשמוצג חתך או ניתוח ההדגשה נשארת, וחלק שנגרר לאורך המפרקים שלו לעולם אינו מדגיש.",
"prefs.navigation": "ניווט",
"prefs.navigation.axes_signed": "צירים",
"prefs.navigation.cube_compact": "קובייה",
"prefs.navigation.device": "התקן",
"prefs.navigation.free": "חופשי",
"prefs.navigation.orbit_style": "סגנון סיבוב",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "שולחן מסתובב",
"prefs.navigation_note": "איך העכבר, משטח המגע והעכבר התלת־ממדי מזיזים את המבט.",
"prefs.navigator_fit": "התאמת המודל לאחר שינוי תצוגה בניווט התצוגה",
"prefs.navigator_fit_note": "לחיצה על פאה, פינה או חץ בנווט, או על ציר בגיזמו, גם מביטה אל מרכז המודל מהמרחק האחד שמכיל אותו מכל צד (הכדור החוסם שלו). תצוגת בית משתמשת באותו זום ובאותו מרכז כל עוד זה פעיל, כך שתצוגות שנבחרות אחריה רק מסתובבות. כבוי: התצוגה מסתובבת במקומה ושומרת על היעד ועל הזום.",
"prefs.navigator_fit_note": "לחיצה על פאה, פינה או חץ בקובייה, או על ציר בגיזמו, גם מביטה אל מרכז המודל מהמרחק האחד שמכיל אותו מכל צד (הכדור החוסם שלו). תצוגת בית משתמשת באותו זום ובאותו מרכז כל עוד זה פעיל, כך שתצוגות שנבחרות אחריה רק מסתובבות. כבוי: התצוגה מסתובבת במקומה ושומרת על היעד ועל הזום.",
"prefs.network_host_remove": "הסרה",
"prefs.network_locations": "התרת מיקומי רשת בתכנים",
"prefs.network_locations_note": "לארגונים השומרים תכנונים בשרתי קבצים. כשהאפשרות כבויה: רק שרתים שאישרתם.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Prijavi problem…",
"Cross curves": "Krivulje presjeka",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter nastavlja na GitHubu.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Trenutni ortografski prikaz (1:1 mm)",
"Current perspective view": "Trenutni perspektivni prikaz",
"Current plane": "Trenutna ravnina",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Kako SolidCraft izgleda i gdje su njegovi dijelovi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrni zakrivljene strelice za valjanje",
"prefs.invert_curved_roll_arrows_note": "Dvije zakrivljene strelice u kutu kocke valjaju prikaz unutar ravnine zaslona. Uključeno: strelica u smjeru kazaljke na satu valja prikaz suprotno od smjera kazaljke na satu, a strelica suprotno od smjera kazaljke na satu valja ga u smjeru kazaljke na satu. Isključeno: svaka strelica valja prikaz onako kako je zakrivljena.",
"prefs.invert_navigator_arrows": "Obrni strelice za rotaciju kocke prikaza",
"prefs.invert_navigator_arrows_note": "Strelice oko kocke orbitiraju kameru u smjeru u kojem pokazuju, kao u programima Fusion i Inventor: strelica s lijeve strane pokazuje udesno i zakreće kameru udesno. Isključeno: strelica okreće kocku prema strani na kojoj se nalazi, pa lijeva strelica zakreće kameru ulijevo. Postavka ne utječe na zakrivljene strelice za valjanje.",
"prefs.keep_work_on_tab_switch": "Zadrži dijaloge i alate otvorenima pri prebacivanju između dizajna",
"prefs.keep_work_on_tab_switch_note": "Svaka kartica dizajna zadržava svoj otvoreni dijalog ili alat, s onim što ste u njemu odabrali i upisali, te svoju karticu alatne trake. Kad se vratite na dizajn, ponovno su tu. Isključeno: prebacivanje između dizajna poništava ih i prikazuje karticu Model.",
"prefs.labels": "Oznake",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigacija",
"prefs.navigation_note": "Kako miš, dodirna pločica i 3D miš pomiču prikaz.",
"prefs.navigator_fit": "Uklopi model nakon promjene prikaza u navigatoru",
"prefs.navigator_fit_note": "Lice, kut ili strelica kocke prikaza, odnosno os orijentacijskog gizma, također usmjerava pogled na sredinu modela s jedne udaljenosti na kojoj se uklapa iz svakog smjera (njegova granična sfera). Početni prikaz koristi isti zum i središte dok je ova opcija uključena, pa se prikazi koje odaberete poslije njega samo okreću. Isključeno: prikaz se okreće na mjestu i zadržava svoj cilj i zum.",
"prefs.network_host_remove": "Ukloni",
"prefs.network_locations": "Dopusti mrežne lokacije u dizajnima",
"prefs.network_locations_note": "Isključeno: povezane datoteke dizajna na drugom računalu (\\\\server\\share) otvaraju se samo s poslužitelja navedenih ovdje ili nakon što ga dopustite kad se to zatraži.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Hibajegy létrehozása…",
"Cross curves": "Keresztgörbék",
"Ctrl+Enter continues on GitHub.": "A Ctrl+Enter a GitHubon folytatja.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Aktuális ortografikus nézet (1:1 mm)",
"Current perspective view": "Aktuális perspektivikus nézet",
"Current plane": "Aktuális sík",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "A SolidCraft megjelenése és elemeinek elhelyezése.",
"prefs.interval_minutes": "{n} perc",
"prefs.invert_curved_roll_arrows": "Az íves gördülőnyilak megfordítása",
"prefs.invert_curved_roll_arrows_note": "A nézetkocka sarkában lévő két íves nyíl a nézetet a képernyő síkjában gördíti. Be: az óramutató járásával megegyező nyíl ellentétes irányba gördít, az ellentétes nyíl pedig az óramutató járásával megegyező irányba. Ki: minden nyíl abba az irányba gördíti a nézetet, amerre ível.",
"prefs.invert_navigator_arrows": "A nézetkocka forgatónyilainak megfordítása",
"prefs.invert_navigator_arrows_note": "A kocka körüli nyilak úgy keringetik a kamerát, ahogy mutatnak, mint a Fusion és az Inventor esetében: a bal oldali nyíl jobbra mutat, és a kamerát jobbra lendíti. Ki: a nyíl a kockát afelé az oldal felé forgatja, amelyiken van, így a bal nyíl a kamerát balra lendíti. Az íves gördülőnyilakat ez nem érinti.",
"prefs.keep_work_on_tab_switch": "A párbeszédablakok és eszközök nyitva tartása tervek közötti váltáskor",
"prefs.keep_work_on_tab_switch_note": "Minden tervfül megtartja a nyitott párbeszédablakát vagy eszközét azzal együtt, amit kijelölt és beírt benne, valamint a menüszalag-fülét. A tervhez visszatérve újra ott vannak. Ki: a tervek közötti váltás megszakítja őket, és a Modell fület mutatja.",
"prefs.labels": "Feliratok",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigáció",
"prefs.navigation_note": "Hogyan mozgatja a nézetet az egér, az érintőpad és a 3D-egér.",
"prefs.navigator_fit": "A modell illesztése navigátornézet-váltás után",
"prefs.navigator_fit_note": "A nézetkocka egy lapja, sarka vagy nyila, illetve a gizmo egy tengelye a modell közepére is ránéz abból az egyetlen távolságból, amelyből minden oldalról belefér (a határoló gömbje). Amíg ez be van kapcsolva, a Kezdőnézet ugyanazt a nagyítást és középpontot használja, így az utána választott nézetek csak elfordulnak. Ki: a nézet a helyén fordul el, megtartva a célpontját és a nagyítását.",
"prefs.network_host_remove": "Eltávolítás",
"prefs.network_locations": "Hálózati helyek engedélyezése a tervekben",
"prefs.network_locations_note": "Ki: egy terv másik számítógépen lévő hivatkozott fájljai (\\\\server\\share) csak az itt felsorolt kiszolgálókról nyílnak meg, vagy miután kérdésre engedélyez egyet.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Buat Issue…",
"Cross curves": "Kurva silang",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter melanjutkan di GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Tampilan ortografis saat ini (1:1 mm)",
"Current perspective view": "Tampilan perspektif saat ini",
"Current plane": "Bidang saat ini",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Tampilan SolidCraft dan letak bagian-bagiannya.",
"prefs.interval_minutes": "{n} mnt",
"prefs.invert_curved_roll_arrows": "Balikkan panah roll melengkung",
"prefs.invert_curved_roll_arrows_note": "Dua panah melengkung di sudut kubus memutar (roll) tampilan di dalam bidang layar. Aktif: panah searah jarum jam memutar berlawanan arah jarum jam dan panah berlawanan arah jarum jam memutar searah jarum jam. Mati: tiap panah memutar tampilan sesuai arah lengkungannya.",
"prefs.invert_navigator_arrows": "Balikkan panah rotasi kubus tampilan",
"prefs.invert_navigator_arrows_note": "Panah di sekeliling kubus memutar orbit kamera ke arah yang ditunjuknya, seperti di Fusion dan Inventor: panah di kiri menunjuk ke kanan dan mengayunkan kamera ke kanan. Mati: panah memutar kubus ke sisi tempatnya berada, sehingga panah kiri mengayunkan kamera ke kiri. Panah roll yang melengkung tidak terpengaruh.",
"prefs.keep_work_on_tab_switch": "Biarkan dialog dan alat tetap terbuka saat berpindah desain",
"prefs.keep_work_on_tab_switch_note": "Setiap tab desain mempertahankan dialog atau alat yang terbuka, beserta apa yang Anda pilih dan ketik di dalamnya, dan tab toolbar-nya. Semuanya kembali saat Anda kembali ke desain itu. Mati: berpindah desain membatalkannya dan menampilkan tab Model.",
"prefs.labels": "Label",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasi",
"prefs.navigation_note": "Cara mouse, trackpad, dan mouse 3D menggerakkan tampilan.",
"prefs.navigator_fit": "Buat model pas di tampilan setelah perubahan tampilan lewat navigator",
"prefs.navigator_fit_note": "Sebuah muka, sudut, atau panah pada kubus tampilan, atau sumbu pada gizmo, juga menghadap ke tengah model dari satu jarak yang membuatnya pas dari segala sisi (bola pembatasnya). Awal memakai zoom dan pusat yang sama selama opsi ini aktif, sehingga tampilan yang dipilih setelahnya hanya berputar. Mati: tampilan berputar di tempat, dengan target dan zoom tetap.",
"prefs.network_host_remove": "Hapus",
"prefs.network_locations": "Izinkan lokasi jaringan di desain",
"prefs.network_locations_note": "Nonaktif: file tertaut sebuah desain di komputer lain (\\\\server\\share) hanya dibuka dari server yang tercantum di sini, atau setelah Anda mengizinkan salah satunya saat ditanya.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crea segnalazione…",
"Cross curves": "Curve trasversali",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continua su GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortografica corrente (1:1 mm)",
"Current perspective view": "Vista prospettica corrente",
"Current plane": "Piano corrente",
@@ -2682,6 +2683,9 @@
"prefs.interface_note": "Aspetto di SolidCraft e disposizione dei suoi elementi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverti le frecce curve di rollio",
"prefs.invert_curved_roll_arrows_note": "Le due frecce curve all'angolo del cubo fanno ruotare la vista nel piano dello schermo. Attivato: la freccia oraria ruota in senso antiorario e la freccia antioraria ruota in senso orario. Disattivato: ogni freccia ruota la vista nel verso in cui si curva.",
"prefs.invert_navigator_arrows": "Inverti le frecce di rotazione del cubo della vista",
"prefs.invert_navigator_arrows_note": "Le frecce attorno al cubo fanno orbitare la camera nella direzione in cui puntano, come in Fusion e Inventor: la freccia a sinistra punta a destra e sposta la camera a destra. Disattivato: una freccia ruota il cubo verso il lato in cui si trova, quindi la freccia sinistra sposta la camera a sinistra. Le frecce curve di rollio non sono interessate.",
"prefs.keep_unsaved_also_asks": "Chiedi comunque alla chiusura della scheda",
"prefs.keep_unsaved_also_asks_tip": "Se disattivato, la scheda si chiude senza la finestra del browser quando la copia di ogni progetto non salvato è aggiornata.",
"prefs.keep_unsaved_in_browser": "Conserva il lavoro non salvato in questo browser",
@@ -2741,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Disattivato: mentre le frecce di Sposta trascinano un componente, niente sotto il puntatore viene evidenziato, così i grandi assiemi restano fluidi. Con una sezione o un'analisi visibile viene evidenziato comunque, e un pezzo trascinato lungo i suoi giunti non lo evidenzia mai.",
"prefs.navigation": "Navigazione",
"prefs.navigation.axes_signed": "Assi",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Libera",
"prefs.navigation.orbit_style": "Stile di orbita",
@@ -2748,6 +2753,7 @@
"prefs.navigation.turntable": "Piatto girevole",
"prefs.navigation_note": "Come mouse, trackpad e mouse 3D spostano la vista.",
"prefs.navigator_fit": "Adatta il modello dopo un cambio di vista dal navigatore",
"prefs.navigator_fit_note": "Una faccia, un angolo o una freccia del cubo della vista, o un asse del gizmo, guarda anche il centro del modello dall'unica distanza che lo inquadra da ogni lato (la sua sfera di ingombro). Inizio usa lo stesso zoom e lo stesso centro finché questa opzione è attiva, quindi le viste scelte dopo si limitano a ruotare. Disattivato: la vista ruota sul posto, mantenendo punto di mira e zoom.",
"prefs.network_host_remove": "Rimuovi",
"prefs.network_locations": "Consenti posizioni di rete nei progetti",
"prefs.network_locations_note": "Disattivato: i file collegati di un progetto su un altro computer (\\\\server\\share) vengono aperti solo dai server elencati qui, o dopo che ne consenti uno quando richiesto.",
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Issueを作成…",
"Cross curves": "交差する曲線",
"Ctrl+Enter continues on GitHub.": "Ctrl+EnterでGitHubに進みます。",
"Cube": "キューブ",
"Current orthographic view (1:1 mm)": "現在の平行投影(実寸・mm)",
"Current perspective view": "現在の透視投影",
"Current plane": "現在の平面",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "SolidCraft の外観と各パネルの配置。",
"prefs.interval_minutes": "{n} 分",
"prefs.invert_curved_roll_arrows": "カーブしたロール矢印を反転",
"prefs.invert_curved_roll_arrows_note": "ナビゲーターの隅にある2つのカーブした矢印は、画面内でビューをロールします。オン: 時計回りの矢印が反時計回りに、反時計回りの矢印が時計回りにロールします。オフ: 各矢印は、そのカーブの向きにビューをロールします。",
"prefs.invert_navigator_arrows": "ナビゲーターの回転矢印を反転",
"prefs.invert_navigator_arrows_note": "ナビゲーターの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、その側へビューを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
"prefs.invert_curved_roll_arrows_note": "キューブの隅にある2つのカーブした矢印は、画面内でビューをロールします。オン: 時計回りの矢印が反時計回りに、反時計回りの矢印が時計回りにロールします。オフ: 各矢印は、そのカーブの向きにビューをロールします。",
"prefs.invert_navigator_arrows": "ビューキューブの回転矢印を反転",
"prefs.invert_navigator_arrows_note": "キューブの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、そのある面の方へキューブを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
"prefs.keep_unsaved_also_asks": "タブを閉じるときにも確認する",
"prefs.keep_unsaved_also_asks_tip": "オフにすると、未保存の各デザインのコピーが最新であれば、ブラウザーの確認なしでタブが閉じます。",
"prefs.keep_unsaved_in_browser": "未保存の作業をこのブラウザーに保持する",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "オフ: 移動の矢印でコンポーネントをドラッグしている間はポインターの下をハイライトしないため、大きなアセンブリでも滑らかに動きます。断面や解析を表示中は通常どおりハイライトし、ジョイントに沿ってドラッグする部品ではハイライトしません。",
"prefs.navigation": "ナビゲーション",
"prefs.navigation.axes_signed": "軸",
"prefs.navigation.cube_compact": "キューブ",
"prefs.navigation.device": "デバイス",
"prefs.navigation.free": "自由",
"prefs.navigation.orbit_style": "回転方式",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "ターンテーブル",
"prefs.navigation_note": "マウス、トラックパッド、3Dマウスによるビューの操作。",
"prefs.navigator_fit": "ナビゲーターでの視点変更後にモデルを全体表示",
"prefs.navigator_fit_note": "ナビゲーターの面・角・矢印やギズモの軸をクリックすると、どの方向からでも全体が収まる一定の距離(外接球)からモデルの中心を見ます。オンの間はホームビューも同じズームと中心を使うため、その後に選んだ視点は向きだけが変わります。オフ: 視点はその場で回転し、注視点とズームを保ちます。",
"prefs.navigator_fit_note": "キューブの面・角・矢印やギズモの軸をクリックすると、どの方向からでも全体が収まる一定の距離(外接球)からモデルの中心を見ます。オンの間はホームビューも同じズームと中心を使うため、その後に選んだ視点は向きだけが変わります。オフ: 視点はその場で回転し、注視点とズームを保ちます。",
"prefs.network_host_remove": "削除",
"prefs.network_locations": "デザイン内のネットワーク上の場所を許可",
"prefs.network_locations_note": "ファイルサーバーでデザインを管理する組織向け。オフの場合は許可したサーバーのみ。",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "შეტყობინების შექმნა…",
"Cross curves": "განივი მრუდები",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter-ით GitHub-ზე გააგრძელებთ.",
"Cube": "კუბი",
"Current orthographic view (1:1 mm)": "მიმდინარე ორთოგრაფიული ხედი (1:1 mm)",
"Current perspective view": "მიმდინარე პერსპექტიული ხედი",
"Current plane": "მიმდინარე სიბრტყე",
@@ -2315,6 +2316,9 @@
"prefs.interface_note": "როგორ გამოიყურება SolidCraft და სად არის მისი ნაწილები.",
"prefs.interval_minutes": "{n} წთ",
"prefs.invert_curved_roll_arrows": "გორების მრუდე ისრების შებრუნება",
"prefs.invert_curved_roll_arrows_note": "კუბის კუთხესთან მდებარე ორი მრუდე ისარი ხედს ეკრანის სიბრტყეში აგორებს. ჩართული: საათის ისრის მიმართულების ისარი საათის ისრის საწინააღმდეგოდ აგორებს, საწინააღმდეგო კი — საათის ისრის მიმართულებით. გამორთული: თითოეული ისარი ხედს თავისი მოხრის მიმართულებით აგორებს.",
"prefs.invert_navigator_arrows": "ხედის კუბის ბრუნვის ისრების შებრუნება",
"prefs.invert_navigator_arrows_note": "კუბის გარშემო ისრები კამერას ორბიტაზე იმ მიმართულებით ატრიალებს, საითაც მიუთითებს, როგორც Fusion-სა და Inventor-ში: მარცხენა ისარი მარჯვნივ მიუთითებს და კამერას მარჯვნივ აბრუნებს. გამორთული: ისარი კუბს იმ მხრისკენ აბრუნებს, რომელზეც მდებარეობს, ამიტომ მარცხენა ისარი კამერას მარცხნივ აბრუნებს. გორების მრუდე ისრებზე ეს არ მოქმედებს.",
"prefs.keep_work_on_tab_switch": "პროექტებს შორის გადართვისას დიალოგებისა და ხელსაწყოების ღიად დატოვება",
"prefs.keep_work_on_tab_switch_note": "პროექტის თითოეული ჩანართი ინარჩუნებს თავის ღია დიალოგს ან ხელსაწყოს, მასში არჩეულსა და აკრეფილს, და ხელსაწყოთა ზოლის ჩანართს. პროექტში დაბრუნებისას ისინი ისევ იქ დაგხვდებათ. გამორთული: პროექტების გადართვა მათ აუქმებს და „მოდელის“ ჩანართს აჩვენებს.",
"prefs.labels": "წარწერები",
@@ -2351,6 +2355,7 @@
"prefs.navigation": "ნავიგაცია",
"prefs.navigation_note": "როგორ ამოძრავებს ხედს მაუსი, სენსორული პანელი და 3D მაუსი.",
"prefs.navigator_fit": "ნავიგატორით ხედის შეცვლის შემდეგ მოდელის ჩატევა",
"prefs.navigator_fit_note": "ხედის კუბის წახნაგი, კუთხე ან ისარი, ან მანიპულატორის ღერძი ასევე მოდელის შუაგულს უყურებს ერთი მანძილიდან, საიდანაც ის ყველა მხრიდან ეტევა (მისი შემომსაზღვრელი სფერო). სანამ ეს ჩართულია, საწყისი ხედი იმავე მასშტაბსა და ცენტრს იყენებს, ამიტომ მის შემდეგ არჩეული ხედები მხოლოდ ბრუნავს. გამორთული: ხედი ადგილზე ბრუნავს, სამიზნისა და მასშტაბის შენარჩუნებით.",
"prefs.network_host_remove": "წაშლა",
"prefs.network_locations": "პროექტებში ქსელური მდებარეობების დაშვება",
"prefs.network_locations_note": "ორგანიზაციებისთვის, რომლებიც პროექტებს ფაილურ სერვერებზე ინახავენ. გამორთული: მხოლოდ თქვენ მიერ დაშვებული სერვერები.",
+3
View File
@@ -151,6 +151,7 @@
"Create Issue — review draft": "이슈 만들기 — 초안 검토",
"Create Issue…": "이슈 만들기…",
"Cross curves": "교차 곡선",
"Cube": "큐브",
"Current orthographic view (1:1 mm)": "현재 직교 투영 뷰 (1:1 mm)",
"Current perspective view": "현재 원근 투영 뷰",
"Current plane": "현재 평면",
@@ -2082,6 +2083,7 @@
"prefs.move_drag_highlights_tip": "끄면 이동 화살표로 구성 요소를 끄는 동안 포인터 아래 항목을 강조 표시하지 않아 큰 어셈블리도 부드럽게 움직입니다. 단면이나 해석이 표시된 동안에는 그대로 강조 표시하며, 조인트를 따라 끄는 부품은 강조 표시하지 않습니다.",
"prefs.navigation": "탐색",
"prefs.navigation.axes_signed": "축",
"prefs.navigation.cube_compact": "큐브",
"prefs.navigation.device": "장치",
"prefs.navigation.free": "자유",
"prefs.navigation.orbit_style": "회전 방식",
@@ -2089,6 +2091,7 @@
"prefs.navigation.turntable": "턴테이블",
"prefs.navigation_note": "마우스, 트랙패드, 3D 마우스로 뷰를 움직이는 방식입니다.",
"prefs.navigator_fit": "뷰 탐색기로 뷰를 바꾼 뒤 모델 맞춤",
"prefs.navigator_fit_note": "큐브의 면, 모서리, 화살표나 기즈모의 축을 클릭하면 어느 방향에서든 전체가 들어가는 한 거리(경계 구)에서 모델의 중심을 바라봅니다. 켜져 있는 동안 홈 뷰도 같은 확대/축소와 중심을 쓰므로 그 뒤에 고른 뷰는 방향만 바뀝니다. 끄면 뷰가 제자리에서 회전하며 대상과 확대/축소를 유지합니다.",
"prefs.network_locations_note": "파일 서버에 디자인을 보관하는 조직용입니다. 끄면 허용한 서버만 사용합니다.",
"prefs.not_on_gpu": "이 GPU에서는 사용할 수 없음",
"prefs.on": "켜짐",
File diff suppressed because it is too large Load Diff
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Cipta Isu…",
"Cross curves": "Lengkung silang",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter meneruskan di GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Pandangan ortografik semasa (1:1 mm)",
"Current perspective view": "Pandangan perspektif semasa",
"Current plane": "Satah semasa",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Rupa SolidCraft dan kedudukan bahagiannya.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Songsangkan anak panah gelek melengkung",
"prefs.invert_curved_roll_arrows_note": "Dua anak panah melengkung di sudut kubus menggelek pandangan dalam satah skrin. Hidup: anak panah ikut arah jam menggelek lawan arah jam dan anak panah lawan arah jam menggelek ikut arah jam. Mati: setiap anak panah menggelek pandangan mengikut arah lengkungannya.",
"prefs.invert_navigator_arrows": "Songsangkan anak panah putaran kubus pandangan",
"prefs.invert_navigator_arrows_note": "Anak panah di sekeliling kubus mengorbit kamera mengikut arah yang ditunjuknya, seperti dalam Fusion dan Inventor: anak panah di kiri menunjuk ke kanan dan mengayunkan kamera ke kanan. Mati: anak panah memutarkan kubus ke arah sisi tempat ia berada, jadi anak panah kiri mengayunkan kamera ke kiri. Anak panah gelek yang melengkung tidak terjejas.",
"prefs.keep_work_on_tab_switch": "Kekalkan dialog dan alat terbuka apabila menukar reka bentuk",
"prefs.keep_work_on_tab_switch_note": "Setiap tab reka bentuk mengekalkan dialog atau alat yang dibukanya, bersama apa yang anda pilih dan taip di dalamnya, serta tab bar alatnya. Semuanya ada semula apabila anda kembali ke reka bentuk itu. Mati: menukar reka bentuk membatalkannya dan menunjukkan tab Model.",
"prefs.labels": "Label",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasi",
"prefs.navigation_note": "Cara tetikus, pad jejak dan tetikus 3D menggerakkan pandangan.",
"prefs.navigator_fit": "Muatkan model selepas perubahan pandangan navigator",
"prefs.navigator_fit_note": "Muka, sudut atau anak panah pada kubus pandangan, atau paksi pada gizmo, turut menghadap ke tengah model dari satu jarak yang memuatkannya dari semua sisi (sfera pembatasnya). Utama menggunakan zum dan pusat yang sama selagi ini dihidupkan, jadi pandangan yang dipilih selepasnya hanya berputar. Mati: pandangan berputar di tempat, dengan sasaran dan zumnya kekal.",
"prefs.network_host_remove": "Buang",
"prefs.network_locations": "Benarkan lokasi rangkaian dalam reka bentuk",
"prefs.network_locations_note": "Dimatikan: fail terpaut bagi reka bentuk pada komputer lain (\\\\server\\share) hanya dibuka daripada pelayan yang disenaraikan di sini, atau selepas anda membenarkannya apabila ditanya.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Opprett sak…",
"Cross curves": "Tverrkurver",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsetter på GitHub.",
"Cube": "Kube",
"Current orthographic view (1:1 mm)": "Gjeldende ortografisk visning (1:1 mm)",
"Current perspective view": "Gjeldende perspektivvisning",
"Current plane": "Gjeldende plan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Hvordan SolidCraft ser ut, og hvor delene er plassert.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter de krumme rullepilene",
"prefs.invert_curved_roll_arrows_note": "De to krumme pilene i hjørnet av kuben ruller visningen i skjermplanet. På: pilen med klokken ruller mot klokken, og pilen mot klokken ruller med klokken. Av: hver pil ruller visningen i den retningen den krummer seg.",
"prefs.invert_navigator_arrows": "Inverter rotasjonspilene på visningskuben",
"prefs.invert_navigator_arrows_note": "Pilene rundt kuben roterer kameraet i den retningen de peker, som i Fusion og Inventor: pilen til venstre peker mot høyre og svinger kameraet mot høyre. Av: en pil roterer kuben mot siden den står på, så venstre pil svinger kameraet mot venstre. De krumme rullepilene påvirkes ikke.",
"prefs.keep_work_on_tab_switch": "Behold dialoger og verktøy åpne når du bytter design",
"prefs.keep_work_on_tab_switch_note": "Hver designfane beholder sin åpne dialog eller sitt åpne verktøy, med det du har valgt og skrevet i den, og sin fane på båndet. De er der igjen når du kommer tilbake til designet. Av: å bytte design avbryter dem og viser fanen Modell.",
"prefs.labels": "Etiketter",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasjon",
"prefs.navigation_note": "Hvordan mus, styreflate og 3D-mus beveger visningen.",
"prefs.navigator_fit": "Tilpass modellen etter en visningsendring fra navigatoren",
"prefs.navigator_fit_note": "En flate, et hjørne eller en pil på visningskuben, eller en akse på orienteringsindikatoren, ser også mot midten av modellen fra den ene avstanden som får den til å passe fra alle sider (den omsluttende kulen). Hjem bruker samme zoom og senter mens dette er på, så visninger som velges etterpå bare dreier. Av: visningen dreier på stedet og beholder målpunktet og zoomen sin.",
"prefs.network_host_remove": "Fjern",
"prefs.network_locations": "Tillat nettverksplasseringer i design",
"prefs.network_locations_note": "Av: lenkede filer i et design på en annen datamaskin (\\\\server\\share) åpnes bare fra serverne som er oppført her, eller etter at du har tillatt en når du blir spurt.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Issue aanmaken…",
"Cross curves": "Kruiscurven",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter gaat verder op GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Huidige orthografische weergave (1:1 mm)",
"Current perspective view": "Huidige perspectiefweergave",
"Current plane": "Huidig vlak",
@@ -2250,6 +2251,9 @@
"prefs.interface_note": "Hoe SolidCraft eruitziet en waar de onderdelen staan.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "De gebogen rolpijlen omkeren",
"prefs.invert_curved_roll_arrows_note": "De twee gebogen pijlen op de hoek van de kubus laten de weergave in het schermvlak rollen. Aan: de pijl met de klok mee rolt tegen de klok in en de pijl tegen de klok in rolt met de klok mee. Uit: elke pijl rolt de weergave in de richting waarin hij krult.",
"prefs.invert_navigator_arrows": "De rotatiepijlen van de weergavekubus omkeren",
"prefs.invert_navigator_arrows_note": "De pijlen rond de kubus laten de camera roteren in de richting waarin ze wijzen, zoals in Fusion en Inventor: de pijl links wijst naar rechts en zwaait de camera naar rechts. Uit: een pijl draait de kubus naar de kant waar hij staat, dus de linkerpijl zwaait de camera naar links. De gebogen rolpijlen worden hierdoor niet beïnvloed.",
"prefs.keep_work_on_tab_switch": "Dialoogvensters en gereedschappen open houden bij het wisselen van ontwerp",
"prefs.keep_work_on_tab_switch_note": "Elk ontwerptabblad behoudt zijn geopende dialoogvenster of gereedschap, met wat je erin hebt gekozen en getypt, en zijn lint-tabblad. Ze zijn er weer als je terugkeert naar het ontwerp. Uit: wisselen van ontwerp breekt ze af en toont het tabblad Model.",
"prefs.labels": "Labels",
@@ -2286,6 +2290,7 @@
"prefs.navigation": "Navigatie",
"prefs.navigation_note": "Hoe de muis, het trackpad en de 3D-muis de weergave verplaatsen.",
"prefs.navigator_fit": "Het model passend in beeld brengen na een wijziging van de navigatorweergave",
"prefs.navigator_fit_note": "Een vlak, hoek of pijl van de weergavekubus, of een as van de gizmo, kijkt ook naar het midden van het model, vanaf de ene afstand waarop het van alle kanten in beeld past (de omsluitende bol). Beginweergave gebruikt dezelfde zoom en hetzelfde middelpunt zolang dit aan staat, zodat weergaven die je daarna kiest alleen draaien. Uit: de weergave draait ter plaatse en behoudt het richtpunt en de zoom.",
"prefs.network_host_remove": "Verwijderen",
"prefs.network_locations": "Netwerklocaties in ontwerpen toestaan",
"prefs.network_locations_note": "Uit: gekoppelde bestanden van een ontwerp op een andere computer (\\\\server\\share) worden alleen geopend vanaf de servers in deze lijst, of nadat je er een toestaat wanneer erom wordt gevraagd.",
@@ -1,21 +0,0 @@
{
"en": { "ui.agent_chat_snap_none_found": "No coding agent found. The Snap package is confined, so it cannot see or start the coding agents installed on this computer. To use them, install SolidCraft from the AppImage, .deb or .rpm package instead. An agent that uses an OpenAI-compatible API works in the Snap package too: set one up with Add agent." },
"ar": { "ui.agent_chat_snap_none_found": "لم يُعثر على وكيل برمجي. تعمل حزمة Snap في بيئة معزولة، لذا لا يمكنها رؤية الوكلاء البرمجيين المثبّتين على هذا الحاسوب ولا تشغيلهم. لاستخدامهم، ثبّت SolidCraft من حزمة AppImage أو .deb أو .rpm بدلًا من ذلك. يعمل الوكيل الذي يستخدم واجهة برمجية متوافقة مع OpenAI في حزمة Snap أيضًا: أعدّه من «إضافة وكيل»." },
"cs": { "ui.agent_chat_snap_none_found": "Nebyl nalezen žádný kódovací agent. Balíček Snap běží v izolovaném prostředí, takže nevidí kódovací agenty nainstalované v tomto počítači a nemůže je spustit. Chcete-li je používat, nainstalujte SolidCraft z balíčku AppImage, .deb nebo .rpm. Agent, který používá API kompatibilní s OpenAI, v balíčku Snap funguje: nastavte ho přes Přidat agenta." },
"de": { "ui.agent_chat_snap_none_found": "Kein Coding-Agent gefunden. Das Snap-Paket ist abgeschottet und kann die auf diesem Computer installierten Coding-Agenten weder sehen noch starten. Um sie zu nutzen, installieren Sie SolidCraft stattdessen aus dem AppImage-, .deb- oder .rpm-Paket. Ein Agent, der eine OpenAI-kompatible API nutzt, funktioniert auch im Snap-Paket: Richten Sie ihn mit Agent hinzufügen ein." },
"es": { "ui.agent_chat_snap_none_found": "No se ha encontrado ningún agente de programación. El paquete Snap está confinado, así que no puede ver ni iniciar los agentes de programación instalados en este equipo. Para usarlos, instala SolidCraft desde el paquete AppImage, .deb o .rpm. Un agente que use una API compatible con OpenAI también funciona en el paquete Snap: configúralo con Añadir agente." },
"fr": { "ui.agent_chat_snap_none_found": "Aucun agent de programmation trouvé. Le paquet Snap est confiné, il ne peut donc ni voir ni lancer les agents de programmation installés sur cet ordinateur. Pour les utiliser, installer plutôt SolidCraft depuis le paquet AppImage, .deb ou .rpm. Un agent qui utilise une API compatible OpenAI fonctionne aussi dans le paquet Snap. Le configurer avec Ajouter un agent." },
"he": { "ui.agent_chat_snap_none_found": "לא נמצא סוכן קוד. חבילת ה־Snap מבודדת, ולכן היא לא יכולה לראות או להפעיל את סוכני הקוד שמותקנים במחשב הזה. כדי להשתמש בהם, יש להתקין את SolidCraft מחבילת AppImage, .deb או .rpm במקום זאת. סוכן שמשתמש ב־API תואם OpenAI עובד גם בחבילת ה־Snap, ואפשר להגדיר אותו בעזרת הוספת סוכן." },
"it": { "ui.agent_chat_snap_none_found": "Nessun agente di programmazione trovato. Il pacchetto Snap è confinato, quindi non può vedere né avviare gli agenti di programmazione installati su questo computer. Per usarli, installa SolidCraft dal pacchetto AppImage, .deb o .rpm. Un agente che usa un’API compatibile con OpenAI funziona anche nel pacchetto Snap: configuralo con Aggiungi agente." },
"ja": { "ui.agent_chat_snap_none_found": "コーディングエージェントが見つかりません。Snap パッケージは制限された環境で動作するため、このコンピューターにインストールされたコーディングエージェントを認識することも起動することもできません。それらを使うには、代わりに AppImage、.deb または .rpm パッケージから SolidCraft をインストールしてください。OpenAI 互換 API を使うエージェントは Snap パッケージでも動作します。「エージェントを追加」から設定してください。" },
"ko": { "ui.agent_chat_snap_none_found": "코딩 에이전트를 찾지 못했습니다. Snap 패키지는 격리된 환경에서 실행되므로 이 컴퓨터에 설치된 코딩 에이전트를 보거나 시작할 수 없습니다. 이 에이전트를 사용하려면 대신 AppImage, .deb 또는 .rpm 패키지로 SolidCraft를 설치하세요. OpenAI 호환 API를 사용하는 에이전트는 Snap 패키지에서도 작동합니다. 에이전트 추가에서 설정하세요." },
"nl": { "ui.agent_chat_snap_none_found": "Geen codeeragent gevonden. Het Snap-pakket is afgeschermd en kan de codeeragents die op deze computer zijn geïnstalleerd niet zien of starten. Installeer SolidCraft in plaats daarvan via het AppImage-, .deb- of .rpm-pakket om ze te gebruiken. Een agent die een OpenAI-compatibele API gebruikt, werkt ook in het Snap-pakket: stel er een in met Agent toevoegen." },
"pl": { "ui.agent_chat_snap_none_found": "Nie znaleziono agenta programistycznego. Pakiet Snap działa w izolacji, więc nie widzi agentów programistycznych zainstalowanych na tym komputerze i nie może ich uruchomić. Aby z nich korzystać, zainstaluj SolidCraft z pakietu AppImage, .deb lub .rpm. Agent korzystający z API zgodnego z OpenAI działa także w pakiecie Snap: skonfiguruj go przyciskiem Dodaj agenta." },
"pt-BR": { "ui.agent_chat_snap_none_found": "Nenhum agente de programação encontrado. O pacote Snap é confinado, então não consegue ver nem iniciar os agentes de programação instalados neste computador. Para usá-los, instale o SolidCraft pelo pacote AppImage, .deb ou .rpm. Um agente que usa uma API compatível com OpenAI também funciona no pacote Snap: configure-o em Adicionar agente." },
"ru": { "ui.agent_chat_snap_none_found": "Кодирующий агент не найден. Пакет Snap работает в изолированной среде, поэтому не видит и не может запускать кодирующих агентов, установленных на этом компьютере. Чтобы пользоваться ими, установите SolidCraft из пакета AppImage, .deb или .rpm. Агент, использующий API, совместимый с OpenAI, работает и в пакете Snap: настройте его через «Добавить агент»." },
"tr": { "ui.agent_chat_snap_none_found": "Kodlama ajanı bulunamadı. Snap paketi yalıtılmış çalıştığı için bu bilgisayarda yüklü kodlama ajanlarını göremez ve başlatamaz. Bunları kullanmak için SolidCraft'ı bunun yerine AppImage, .deb veya .rpm paketinden yükleyin. OpenAI uyumlu API kullanan bir ajan Snap paketinde de çalışır: Ajan ekle ile ayarlayın." },
"uk": { "ui.agent_chat_snap_none_found": "Агента для програмування не знайдено. Пакет Snap працює в ізольованому середовищі, тому не бачить і не може запускати агентів для програмування, установлених на цьому комп’ютері. Щоб користуватися ними, установіть SolidCraft з пакета AppImage, .deb або .rpm. Агент, що використовує API, сумісний з OpenAI, працює і в пакеті Snap: налаштуйте його через «Додати агента»." },
"vi": { "ui.agent_chat_snap_none_found": "Không tìm thấy tác tử lập trình nào. Gói Snap chạy trong môi trường bị giới hạn nên không thể thấy hay khởi động các tác tử lập trình được cài trên máy tính này. Để dùng chúng, hãy cài SolidCraft từ gói AppImage, .deb hoặc .rpm thay vào đó. Tác tử dùng API tương thích OpenAI vẫn hoạt động trong gói Snap: hãy thiết lập bằng Thêm AI Agent." },
"zh": { "ui.agent_chat_snap_none_found": "未找到编程代理。Snap 软件包运行在受限环境中,无法看到或启动此计算机上安装的编程代理。要使用它们,请改用 AppImage、.deb 或 .rpm 软件包安装 SolidCraft。使用 OpenAI 兼容 API 的代理在 Snap 软件包中同样可用:请通过“添加智能体”进行设置。" },
"zh-TW": { "ui.agent_chat_snap_none_found": "未找到程式設計代理。Snap 套件在受限環境中執行,無法看到或啟動這台電腦上安裝的程式設計代理。若要使用它們,請改用 AppImage、.deb 或 .rpm 套件安裝 SolidCraft。使用 OpenAI 相容 API 的代理在 Snap 套件中同樣可用:請透過「新增代理」進行設定。" }
}
@@ -1,18 +0,0 @@
{
"en": { "ui.browser_collapse_below": "Collapse Below", "ui.browser_expand_below": "Expand Below" },
"ar": { "ui.browser_collapse_below": "طي ما بالأسفل", "ui.browser_expand_below": "توسيع ما بالأسفل" },
"de": { "ui.browser_collapse_below": "Darunter einklappen", "ui.browser_expand_below": "Darunter ausklappen" },
"es": { "ui.browser_collapse_below": "Contraer debajo", "ui.browser_expand_below": "Expandir debajo" },
"fr": { "ui.browser_collapse_below": "Réduire en dessous", "ui.browser_expand_below": "Développer en dessous" },
"he": { "ui.browser_collapse_below": "כיווץ מה שמתחת", "ui.browser_expand_below": "הרחבת מה שמתחת" },
"it": { "ui.browser_collapse_below": "Comprimi sotto", "ui.browser_expand_below": "Espandi sotto" },
"ja": { "ui.browser_collapse_below": "この下を折りたたむ", "ui.browser_expand_below": "この下を展開" },
"ko": { "ui.browser_collapse_below": "하위 항목 접기", "ui.browser_expand_below": "하위 항목 펼치기" },
"nl": { "ui.browser_collapse_below": "Onderliggende samenvouwen", "ui.browser_expand_below": "Onderliggende uitvouwen" },
"pl": { "ui.browser_collapse_below": "Zwiń poniżej", "ui.browser_expand_below": "Rozwiń poniżej" },
"ru": { "ui.browser_collapse_below": "Свернуть вложенное", "ui.browser_expand_below": "Развернуть вложенное" },
"uk": { "ui.browser_collapse_below": "Згорнути вкладене", "ui.browser_expand_below": "Розгорнути вкладене" },
"vi": { "ui.browser_collapse_below": "Thu gọn bên dưới", "ui.browser_expand_below": "Mở rộng bên dưới" },
"zh": { "ui.browser_collapse_below": "折叠下级", "ui.browser_expand_below": "展开下级" },
"zh-TW": { "ui.browser_collapse_below": "折疊下層", "ui.browser_expand_below": "展開下層" }
}
@@ -1,22 +0,0 @@
{
"ar": {
"ui.construction.axis_hint": "خط إنشائي: انقر نقطة، أو أدخل بعدها عن محور الرسم",
"ui.construction.parallel_hint": "خط إنشائي: اختر خطًا مستقيمًا ثم انقر أو أدخل الإزاحة؛ انقر بزر الفأرة الأيمن لتغيير المرجع"
},
"he": {
"ui.construction.axis_hint": "ישר עזר: לחיצה על נקודה, או הקלדת המרחק מציר הסקיצה",
"ui.construction.parallel_hint": "ישר עזר: בחירת ישר, ואז לחיצה או הקלדת ההיסט; לחיצה ימנית להחלפת הייחוס"
},
"ja": {
"ui.construction.axis_hint": "補助直線: 点をクリックするか、スケッチ軸からの距離を入力",
"ui.construction.parallel_hint": "補助直線: 直線を選択し、クリックするかオフセットを入力。右クリックで参照を変更"
},
"vi": {
"ui.construction.axis_hint": "Đường dựng hình: nhấp một điểm, hoặc nhập khoảng cách tới trục phác thảo",
"ui.construction.parallel_hint": "Đường dựng hình: chọn đường thẳng, rồi nhấp hoặc nhập khoảng dời; nhấp chuột phải để đổi tham chiếu"
},
"zh": {
"ui.construction.axis_hint": "构造直线:单击一点,或输入它到草图轴的距离",
"ui.construction.parallel_hint": "构造直线:先选直线,再单击或输入偏移;右键单击更换参照"
}
}
@@ -1,34 +0,0 @@
{
"ar": {
"prefs.history_steps_component": "خطوات السجل حسب المكوّن",
"prefs.history_steps_component_note": "عندما يكون مكوّن نشطًا أو محددًا، تتنقل عناصر تحكم السجل بين ميزات ذلك المكوّن كما يعرضها السجل في الأسفل. عند إيقافه تتنقل بين كل ميزات التصميم. السجل على اليسار أو تحت المستعرض يتنقل دائمًا بين كل الميزات."
},
"de": {
"prefs.history_steps_component": "Verlaufsschritte je Komponente",
"prefs.history_steps_component_note": "Ist eine Komponente aktiv oder ausgewählt, gehen die Verlaufssteuerelemente durch deren Features, so wie der Verlauf unten sie zeigt. Aus: Sie gehen durch alle Features des Designs. Der Verlauf links oder unter dem Browser geht immer durch alle Features."
},
"en": {
"prefs.history_steps_component": "History steps by component",
"prefs.history_steps_component_note": "With a component active or picked, the History controls step through that component's features, as the History at the bottom shows them. Off: they step through every feature of the design. The History on the left or under the browser always steps through every feature."
},
"he": {
"prefs.history_steps_component": "צעדי ציר הזמן לפי רכיב",
"prefs.history_steps_component_note": "כשרכיב פעיל או נבחר, פקדי ציר הזמן עוברים בין הפיצ'רים של אותו רכיב, כפי שציר הזמן למטה מציג אותם. כבוי: הם עוברים בין כל הפיצ'רים של התכנון. ציר הזמן משמאל או מתחת לדפדפן עובר תמיד בין כל הפיצ'רים."
},
"ja": {
"prefs.history_steps_component": "コンポーネント単位で履歴を移動",
"prefs.history_steps_component_note": "コンポーネントがアクティブまたは選択されているとき、履歴コントロールは下部の履歴に表示されるとおり、そのコンポーネントのフィーチャだけを移動します。オフにすると、デザインのすべてのフィーチャを移動します。左側またはブラウザー下の履歴は常にすべてのフィーチャを移動します。"
},
"ko": {
"prefs.history_steps_component": "구성 요소별 히스토리 이동",
"prefs.history_steps_component_note": "구성 요소가 활성화되었거나 선택되어 있으면 기록 컨트롤이 아래쪽 히스토리에 보이는 대로 그 구성 요소의 피처만 이동합니다. 끄면 디자인의 모든 피처를 이동합니다. 왼쪽 또는 브라우저 아래의 히스토리는 항상 모든 피처를 이동합니다."
},
"vi": {
"prefs.history_steps_component": "Bước Lịch sử theo cụm chi tiết",
"prefs.history_steps_component_note": "Khi một cụm chi tiết đang kích hoạt hoặc được chọn, các điều khiển Lịch sử đi qua các tính năng của cụm đó, như dòng Lịch sử ở cạnh dưới hiển thị. Tắt: chúng đi qua mọi tính năng của thiết kế. Cây Lịch sử ở bên trái hoặc dưới cây thư mục luôn đi qua mọi tính năng."
},
"zh": {
"prefs.history_steps_component": "历史按组件逐步移动",
"prefs.history_steps_component_note": "当某个组件处于活动或选中状态时,历史控件按底部历史的显示,只在该组件的特征之间移动。关闭后,它们在设计的所有特征之间移动。左侧或浏览器下方的历史始终在所有特征之间移动。"
}
}
@@ -1,47 +0,0 @@
{
"en": {
"measure.perimeter": "Perimeter",
"measure.perimeter_inner": "Inner perimeter",
"measure.perimeter_outer": "Outer perimeter"
},
"ar": {
"measure.perimeter": "المحيط",
"measure.perimeter_inner": "المحيط الداخلي",
"measure.perimeter_outer": "المحيط الخارجي"
},
"de": {
"measure.perimeter": "Umfang",
"measure.perimeter_inner": "Innenumfang",
"measure.perimeter_outer": "Außenumfang"
},
"fr": {
"measure.perimeter": "Périmètre",
"measure.perimeter_inner": "Périmètre intérieur",
"measure.perimeter_outer": "Périmètre extérieur"
},
"he": {
"measure.perimeter": "היקף",
"measure.perimeter_inner": "היקף פנימי",
"measure.perimeter_outer": "היקף חיצוני"
},
"ja": {
"measure.perimeter": "周長",
"measure.perimeter_inner": "内周長",
"measure.perimeter_outer": "外周長"
},
"ko": {
"measure.perimeter": "둘레",
"measure.perimeter_inner": "내부 둘레",
"measure.perimeter_outer": "외부 둘레"
},
"vi": {
"measure.perimeter": "Chu vi",
"measure.perimeter_inner": "Chu vi trong",
"measure.perimeter_outer": "Chu vi ngoài"
},
"zh": {
"measure.perimeter": "周长",
"measure.perimeter_inner": "内周长",
"measure.perimeter_outer": "外周长"
}
}
@@ -1,11 +0,0 @@
{
"ar": { "cmd.inspect_parameter_variants": "مقارنة بدائل المعلمات" },
"de": { "cmd.inspect_parameter_variants": "Parametervarianten vergleichen" },
"en": { "cmd.inspect_parameter_variants": "Compare Parameter Variants" },
"es": { "cmd.inspect_parameter_variants": "Comparar variantes de parámetros" },
"he": { "cmd.inspect_parameter_variants": "השוואת חלופות פרמטרים" },
"ja": { "cmd.inspect_parameter_variants": "パラメーターの組み合わせを比較" },
"ko": { "cmd.inspect_parameter_variants": "매개변수 조합 비교" },
"vi": { "cmd.inspect_parameter_variants": "So sánh các phương án tham số" },
"zh": { "cmd.inspect_parameter_variants": "比较参数方案" }
}
@@ -1,14 +0,0 @@
{
"en": { "ui.properties.copy_value": "Click to copy", "ui.properties.value_copied": "Value copied" },
"ar": { "ui.properties.copy_value": "انقر للنسخ", "ui.properties.value_copied": "تم نسخ القيمة" },
"de": { "ui.properties.copy_value": "Klicken, um den Wert zu kopieren", "ui.properties.value_copied": "Wert kopiert" },
"es": { "ui.properties.copy_value": "Haz clic para copiar", "ui.properties.value_copied": "Valor copiado" },
"fr": { "ui.properties.copy_value": "Cliquer pour copier", "ui.properties.value_copied": "Valeur copiée" },
"he": { "ui.properties.copy_value": "לחיצה מעתיקה את הערך", "ui.properties.value_copied": "הערך הועתק" },
"it": { "ui.properties.copy_value": "Fai clic per copiare", "ui.properties.value_copied": "Valore copiato" },
"ja": { "ui.properties.copy_value": "クリックでコピー", "ui.properties.value_copied": "値をコピーしました" },
"ko": { "ui.properties.copy_value": "클릭하여 복사", "ui.properties.value_copied": "값을 복사했습니다" },
"vi": { "ui.properties.copy_value": "Nhấp để sao chép", "ui.properties.value_copied": "Đã sao chép giá trị" },
"zh": { "ui.properties.copy_value": "点击复制", "ui.properties.value_copied": "已复制数值" },
"zh-TW": { "ui.properties.copy_value": "按一下以複製", "ui.properties.value_copied": "已複製數值" }
}
-82
View File
@@ -1,82 +0,0 @@
{
"ar": {
"document.discard_row": "تجاهل",
"document.finish_save_prompt": "أكمل الرد على نافذة الحفظ قبل فتح تصميم آخر.",
"document.not_saved_yet": "لم يُحفظ بعد",
"document.save_many": "حفظ التغييرات في {n} من التصاميم؟",
"document.save_row": "حفظ",
"document.save_selected": "حفظ المحدد",
"prefs.save_prompt_one_at_a_time": "السؤال عن كل تصميم غير محفوظ على حدة عند إغلاق عدة تصاميم",
"prefs.save_prompt_one_at_a_time_help": "عرض نافذة حفظ لكل تصميم غير محفوظ بدلاً من قائمة مجمّعة."
},
"de": {
"document.discard_row": "Verwerfen",
"document.finish_save_prompt": "Beantworten Sie die Speicherabfrage, bevor Sie einen weiteren Entwurf öffnen.",
"document.not_saved_yet": "Noch nicht gespeichert",
"document.save_many": "Änderungen an {n} Entwürfen speichern?",
"document.save_row": "Speichern",
"document.save_selected": "Auswahl speichern",
"prefs.save_prompt_one_at_a_time": "Beim Schließen mehrerer Entwürfe für jeden ungespeicherten Entwurf einzeln fragen",
"prefs.save_prompt_one_at_a_time_help": "Für jeden ungespeicherten Entwurf eine eigene Speicherabfrage statt einer gemeinsamen Liste anzeigen."
},
"en": {
"document.discard_row": "Discard",
"document.finish_save_prompt": "Finish answering the save prompt before opening another design.",
"document.not_saved_yet": "Not saved yet",
"document.save_many": "Save changes to {n} designs?",
"document.save_row": "Save",
"document.save_selected": "Save Selected",
"prefs.save_prompt_one_at_a_time": "Ask about each unsaved design separately when closing several",
"prefs.save_prompt_one_at_a_time_help": "Show one save prompt per unsaved design instead of a combined list."
},
"he": {
"document.discard_row": "ביטול שינויים",
"document.finish_save_prompt": "יש לסיים לענות על חלון השמירה לפני פתיחת תכן אחר.",
"document.not_saved_yet": "עדיין לא נשמר",
"document.save_many": "לשמור שינויים ב־{n} תכנים?",
"document.save_row": "שמירה",
"document.save_selected": "שמירת הנבחרים",
"prefs.save_prompt_one_at_a_time": "לשאול על כל תכן שלא נשמר בנפרד בעת סגירת כמה",
"prefs.save_prompt_one_at_a_time_help": "להציג חלון שמירה נפרד לכל תכן שלא נשמר במקום רשימה משותפת."
},
"ja": {
"document.discard_row": "破棄",
"document.finish_save_prompt": "別のデザインを開く前に、保存の確認に回答してください。",
"document.not_saved_yet": "未保存",
"document.save_many": "{n} 件のデザインの変更を保存しますか?",
"document.save_row": "保存",
"document.save_selected": "選択項目を保存",
"prefs.save_prompt_one_at_a_time": "複数を閉じるとき、未保存のデザインごとに確認する",
"prefs.save_prompt_one_at_a_time_help": "一覧でまとめて確認する代わりに、未保存のデザインごとに保存を確認します。"
},
"ko": {
"document.discard_row": "버리기",
"document.finish_save_prompt": "다른 디자인을 열기 전에 저장 여부를 선택하세요.",
"document.not_saved_yet": "아직 저장하지 않음",
"document.save_many": "디자인 {n}개의 변경 사항을 저장하시겠습니까?",
"document.save_row": "저장",
"document.save_selected": "선택 항목 저장",
"prefs.save_prompt_one_at_a_time": "여러 디자인을 닫을 때 저장하지 않은 디자인마다 따로 묻기",
"prefs.save_prompt_one_at_a_time_help": "통합 목록 대신 저장하지 않은 디자인마다 저장 여부를 묻습니다."
},
"vi": {
"document.discard_row": "Bỏ thay đổi",
"document.finish_save_prompt": "Hãy trả lời xong hộp thoại lưu trước khi mở thiết kế khác.",
"document.not_saved_yet": "Chưa lưu",
"document.save_many": "Lưu thay đổi cho {n} thiết kế?",
"document.save_row": "Lưu",
"document.save_selected": "Lưu mục đã chọn",
"prefs.save_prompt_one_at_a_time": "Hỏi riêng từng thiết kế chưa lưu khi đóng nhiều thiết kế",
"prefs.save_prompt_one_at_a_time_help": "Hiển thị một hộp thoại lưu cho mỗi thiết kế chưa lưu thay vì một danh sách chung."
},
"zh": {
"document.discard_row": "放弃",
"document.finish_save_prompt": "请先回答保存提示,再打开其他设计。",
"document.not_saved_yet": "尚未保存",
"document.save_many": "保存 {n} 个设计的更改?",
"document.save_row": "保存",
"document.save_selected": "保存所选项",
"prefs.save_prompt_one_at_a_time": "关闭多个设计时,逐个询问未保存的设计",
"prefs.save_prompt_one_at_a_time_help": "对每个未保存的设计分别显示保存提示,而不是合并列表。"
}
}
@@ -1,38 +0,0 @@
{
"en": {
"Segments": "Segments",
"Split Edge": "Split Edge",
"Remove this segment": "Remove this segment",
"One more stretch of the picked edge, each with its own angle, height and turns": "One more stretch of the picked edge, each with its own angle, height and turns"
},
"ar": {
"Segments": "المقاطع",
"Split Edge": "تقسيم الحافة",
"Remove this segment": "إزالة هذا المقطع",
"One more stretch of the picked edge, each with its own angle, height and turns": "مقطع آخر من الحافة المختارة، لكل منها زاويتها وارتفاعها ولفّاتها"
},
"he": {
"Segments": "מקטעים",
"Split Edge": "פיצול המקצוע",
"Remove this segment": "הסרת המקטע הזה",
"One more stretch of the picked edge, each with its own angle, height and turns": "מקטע נוסף של המקצוע הנבחר, שלכל אחד זווית, גובה וכיפופים משלו"
},
"ja": {
"Segments": "セグメント",
"Split Edge": "エッジを分割",
"Remove this segment": "このセグメントを削除",
"One more stretch of the picked edge, each with its own angle, height and turns": "選択したエッジのもう一つの区間。それぞれに独自の角度、高さ、曲げ方向があります"
},
"vi": {
"Segments": "Đoạn",
"Split Edge": "Chia cạnh",
"Remove this segment": "Xóa đoạn này",
"One more stretch of the picked edge, each with its own angle, height and turns": "Thêm một đoạn nữa của cạnh đã chọn, mỗi đoạn có góc, chiều cao và hướng uốn riêng"
},
"zh": {
"Segments": "分段",
"Split Edge": "分割边",
"Remove this segment": "移除此分段",
"One more stretch of the picked edge, each with its own angle, height and turns": "所选边的又一段,每段都有自己的角度、高度和折弯方向"
}
}
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Utwórz zgłoszenie…",
"Cross curves": "Krzywe poprzeczne",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter przechodzi dalej na GitHubie.",
"Cube": "Sześcian",
"Current orthographic view (1:1 mm)": "Bieżący widok ortogonalny (1:1 mm)",
"Current perspective view": "Bieżący widok perspektywiczny",
"Current plane": "Bieżąca płaszczyzna",
@@ -2658,6 +2659,9 @@
"prefs.interface_note": "Wygląd SolidCraft i rozmieszczenie jego elementów.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Odwróć zakrzywione strzałki przechylenia",
"prefs.invert_curved_roll_arrows_note": "Dwie zakrzywione strzałki w rogu kostki przechylają widok w płaszczyźnie ekranu. Włączone: strzałka zgodna z ruchem wskazówek zegara przechyla przeciwnie, a przeciwna – zgodnie. Wyłączone: każda strzałka przechyla widok w stronę, w którą jest zakrzywiona.",
"prefs.invert_navigator_arrows": "Odwróć strzałki obrotu kostki widoku",
"prefs.invert_navigator_arrows_note": "Strzałki wokół kostki obracają kamerę w kierunku, w który wskazują, jak w Fusion i Inventor: strzałka po lewej wskazuje w prawo i obraca kamerę w prawo. Wyłączone: strzałka obraca kostkę w stronę, po której się znajduje, więc lewa strzałka obraca kamerę w lewo. Zakrzywione strzałki przechylenia nie są zmieniane.",
"prefs.keep_unsaved_also_asks": "Mimo to pytaj przy zamykaniu karty",
"prefs.keep_unsaved_also_asks_tip": "Gdy wyłączone, karta zamyka się bez okna przeglądarki, jeśli kopia każdego niezapisanego projektu jest aktualna.",
"prefs.keep_unsaved_in_browser": "Przechowuj niezapisaną pracę w tej przeglądarce",
@@ -2717,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Wyłączone: gdy strzałki Przesuń przeciągają komponent, nic pod wskaźnikiem nie jest podświetlane, co zachowuje płynność dużych złożeń. Przy pokazanym przekroju lub analizie podświetlenie i tak działa, a część przeciągana wzdłuż złączy nigdy go nie podświetla.",
"prefs.navigation": "Nawigacja",
"prefs.navigation.axes_signed": "Osie",
"prefs.navigation.cube_compact": "Kostka",
"prefs.navigation.device": "Urządzenie",
"prefs.navigation.free": "Swobodne",
"prefs.navigation.orbit_style": "Styl obracania",
@@ -2724,6 +2729,7 @@
"prefs.navigation.turntable": "Obrotnica",
"prefs.navigation_note": "Jak mysz, gładzik i mysz 3D poruszają widokiem.",
"prefs.navigator_fit": "Dopasuj model po zmianie widoku w nawigatorze",
"prefs.navigator_fit_note": "Ściana, narożnik lub strzałka kostki widoku albo oś wskaźnika orientacji kieruje też widok na środek modelu z odległości, z której mieści się on z każdej strony (jego sfera otaczająca). Gdy to jest włączone, Widok główny używa tego samego powiększenia i środka, więc widoki wybrane później tylko się obracają. Wyłączone: widok obraca się w miejscu, zachowując cel i powiększenie.",
"prefs.network_host_remove": "Usuń",
"prefs.network_locations": "Zezwalaj na lokalizacje sieciowe w projektach",
"prefs.network_locations_note": "Wyłączone: połączone pliki projektu na innym komputerze (\\\\serwer\\udział) są otwierane tylko z serwerów wymienionych tutaj albo po zezwoleniu, gdy pojawi się pytanie.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Criar issue…",
"Cross curves": "Curvas transversais",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continua no GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica atual (1:1 mm)",
"Current perspective view": "Vista em perspectiva atual",
"Current plane": "Plano atual",
@@ -2658,6 +2659,9 @@
"prefs.interface_note": "A aparência do SolidCraft e onde ficam suas partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter as setas curvas de rolagem",
"prefs.invert_curved_roll_arrows_note": "As duas setas curvas no canto do cubo rolam a vista no plano da tela. Ativado: a seta horária rola no sentido anti-horário e a seta anti-horária rola no sentido horário. Desativado: cada seta rola a vista no sentido em que se curva.",
"prefs.invert_navigator_arrows": "Inverter as setas de rotação do cubo de vista",
"prefs.invert_navigator_arrows_note": "As setas em volta do cubo orbitam a câmera para onde apontam, como no Fusion e no Inventor: a seta da esquerda aponta para a direita e gira a câmera para a direita. Desativado: uma seta gira o cubo em direção ao lado em que está, então a seta da esquerda gira a câmera para a esquerda. As setas curvas de rolagem não são afetadas.",
"prefs.keep_unsaved_also_asks": "Perguntar mesmo assim ao fechar a aba",
"prefs.keep_unsaved_also_asks_tip": "Com isto desativado, a aba fecha sem a caixa do navegador quando a cópia de cada projeto não salvo estiver atualizada.",
"prefs.keep_unsaved_in_browser": "Guardar trabalho não salvo neste navegador",
@@ -2717,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Desativado: enquanto as setas de Mover arrastam um componente, nada sob o ponteiro é destacado, o que mantém montagens grandes fluidas. Com um corte ou uma análise exibidos, o destaque acontece mesmo assim, e uma peça arrastada ao longo de suas juntas nunca o destaca.",
"prefs.navigation": "Navegação",
"prefs.navigation.axes_signed": "Eixos",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Livre",
"prefs.navigation.orbit_style": "Estilo de órbita",
@@ -2724,6 +2729,7 @@
"prefs.navigation.turntable": "Mesa giratória",
"prefs.navigation_note": "Como o mouse, o trackpad e o mouse 3D movem a vista.",
"prefs.navigator_fit": "Ajustar o modelo após uma mudança de vista do navegador",
"prefs.navigator_fit_note": "Uma face, um canto ou uma seta do cubo de vista, ou um eixo do gizmo, também olha para o meio do modelo a partir da distância única que o enquadra de todos os lados (sua esfera envolvente). Início usa o mesmo zoom e centro enquanto isto estiver ativado, então as vistas escolhidas depois só giram. Desativado: a vista gira no lugar, mantendo seu alvo e zoom.",
"prefs.network_host_remove": "Remover",
"prefs.network_locations": "Permitir locais de rede nos projetos",
"prefs.network_locations_note": "Para organizações que mantêm projetos em servidores de arquivos. Desativado: apenas servidores que você permitir.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Creează raport…",
"Cross curves": "Curbe transversale",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continuă pe GitHub.",
"Cube": "Cub",
"Current orthographic view (1:1 mm)": "Vizualizare ortografică curentă (1:1 mm)",
"Current perspective view": "Vizualizare în perspectivă curentă",
"Current plane": "Planul curent",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Cum arată SolidCraft și unde sunt așezate elementele sale.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inversează săgețile curbe de ruliu",
"prefs.invert_curved_roll_arrows_note": "Cele două săgeți curbe din colțul cubului rotesc vizualizarea în planul ecranului. Activat: săgeata în sens orar rotește în sens antiorar, iar săgeata în sens antiorar rotește în sens orar. Dezactivat: fiecare săgeată rotește vizualizarea în direcția în care se curbează.",
"prefs.invert_navigator_arrows": "Inversează săgețile de rotație ale cubului de vizualizare",
"prefs.invert_navigator_arrows_note": "Săgețile din jurul cubului rotesc camera în jurul modelului în direcția în care indică, ca în Fusion și Inventor: săgeata din stânga indică spre dreapta și rotește camera spre dreapta. Dezactivat: o săgeată rotește cubul spre partea pe care se află, deci săgeata din stânga rotește camera spre stânga. Săgețile curbe de ruliu nu sunt afectate.",
"prefs.keep_work_on_tab_switch": "Păstrează deschise dialogurile și instrumentele la schimbarea proiectului",
"prefs.keep_work_on_tab_switch_note": "Fiecare filă de proiect își păstrează dialogul sau instrumentul deschis, cu ce ați ales și ați tastat în el, și fila ei din bara de instrumente. Le regăsiți când reveniți la proiect. Dezactivat: schimbarea proiectului le anulează și afișează fila Model.",
"prefs.labels": "Etichete",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigare",
"prefs.navigation_note": "Cum mută vizualizarea mouse-ul, trackpadul și mouse-ul 3D.",
"prefs.navigator_fit": "Potrivește modelul după o schimbare de vizualizare din navigator",
"prefs.navigator_fit_note": "O față, un colț sau o săgeată a cubului de vizualizare ori o axă a reperului de orientare privește și spre mijlocul modelului, de la singura distanță care îl cuprinde din toate părțile (sfera lui de încadrare). Acasă folosește același zoom și același centru cât timp opțiunea este activată, așa că vizualizările alese după aceea doar se rotesc. Dezactivat: vizualizarea se rotește pe loc, păstrându-și ținta și zoomul.",
"prefs.network_host_remove": "Elimină",
"prefs.network_locations": "Permite locațiile de rețea în proiecte",
"prefs.network_locations_note": "Dezactivat: fișierele legate ale unui proiect aflate pe alt computer (\\\\server\\share) se deschid doar de pe serverele listate aici sau după ce permiteți unul, când vi se cere.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Создать Issue…",
"Cross curves": "Поперечные кривые",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter — продолжить на GitHub.",
"Cube": "Куб",
"Current orthographic view (1:1 mm)": "Текущий ортогональный вид (1:1 мм)",
"Current perspective view": "Текущий перспективный вид",
"Current plane": "Текущая плоскость",
@@ -2231,6 +2232,9 @@
"prefs.interface_note": "Как выглядит SolidCraft и где расположены его части.",
"prefs.interval_minutes": "{n} мин",
"prefs.invert_curved_roll_arrows": "Инвертировать изогнутые стрелки крена",
"prefs.invert_curved_roll_arrows_note": "Две изогнутые стрелки в углу куба поворачивают вид в плоскости экрана. Вкл.: стрелка по часовой стрелке поворачивает вид против часовой, а стрелка против часовой — по часовой. Выкл.: каждая стрелка поворачивает вид в ту сторону, куда она изогнута.",
"prefs.invert_navigator_arrows": "Инвертировать стрелки вращения куба видов",
"prefs.invert_navigator_arrows_note": "Стрелки вокруг куба вращают камеру в ту сторону, куда указывают, как в Fusion и Inventor: стрелка слева указывает вправо и поворачивает камеру вправо. Выкл.: стрелка поворачивает куб в сторону, где она расположена, поэтому левая стрелка поворачивает камеру влево. Изогнутые стрелки крена не затрагиваются.",
"prefs.keep_work_on_tab_switch": "Сохранять открытые диалоги и инструменты при переключении между дизайнами",
"prefs.keep_work_on_tab_switch_note": "Каждая вкладка дизайна сохраняет свой открытый диалог или инструмент вместе с тем, что вы в нём выбрали и ввели, а также свою вкладку панели инструментов. Они снова на месте, когда вы возвращаетесь к дизайну. Выкл.: при переключении дизайнов они отменяются, и показывается вкладка «Модель».",
"prefs.labels": "Подписи",
@@ -2267,6 +2271,7 @@
"prefs.navigation": "Навигация",
"prefs.navigation_note": "Как мышь, тачпад и 3D-мышь двигают вид.",
"prefs.navigator_fit": "Вписывать модель после смены вида в навигаторе",
"prefs.navigator_fit_note": "Грань, угол или стрелка куба видов либо ось гизмо также направляет взгляд на середину модели с единственного расстояния, с которого она целиком видна со всех сторон (её габаритная сфера). «Главная» при включённом параметре использует тот же масштаб и центр, поэтому выбранные после неё виды только поворачиваются. Выкл.: вид поворачивается на месте, сохраняя свою цель и масштаб.",
"prefs.network_host_remove": "Убрать",
"prefs.network_locations": "Разрешить сетевые расположения в дизайнах",
"prefs.network_locations_note": "Выкл.: связанные файлы дизайна на другом компьютере (\\\\server\\share) открываются только с перечисленных здесь серверов или после того, как вы разрешите сервер по запросу.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Пријави проблем…",
"Cross curves": "Пресечне криве",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter наставља на GitHub-у.",
"Cube": "Коцка",
"Current orthographic view (1:1 mm)": "Тренутни ортографски приказ (1:1 mm)",
"Current perspective view": "Тренутни перспективни приказ",
"Current plane": "Тренутна раван",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Како SolidCraft изгледа и где су његови делови.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Обрни закривљене стрелице за ваљање",
"prefs.invert_curved_roll_arrows_note": "Две закривљене стрелице у углу коцке ваљају приказ унутар равни екрана. Укључено: стрелица у смеру казаљке на сату ваља приказ супротно од смера казаљке на сату, а стрелица супротно од смера казаљке на сату ваља га у смеру казаљке на сату. Искључено: свака стрелица ваља приказ онако како је закривљена.",
"prefs.invert_navigator_arrows": "Обрни стрелице за ротацију коцке приказа",
"prefs.invert_navigator_arrows_note": "Стрелице око коцке орбитирају камеру у смеру у којем показују, као у програмима Fusion и Inventor: стрелица са леве стране показује удесно и закреће камеру удесно. Искључено: стрелица окреће коцку ка страни на којој се налази, па лева стрелица закреће камеру улево. Подешавање не утиче на закривљене стрелице за ваљање.",
"prefs.keep_work_on_tab_switch": "Задржи дијалоге и алате отвореним при пребацивању између дизајна",
"prefs.keep_work_on_tab_switch_note": "Свака картица дизајна задржава свој отворени дијалог или алат, са оним што сте у њему изабрали и уписали, те своју картицу траке са алатима. Када се вратите на дизајн, поново су ту. Искључено: пребацивање између дизајна отказује их и приказује картицу Модел.",
"prefs.labels": "Ознаке",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Навигација",
"prefs.navigation_note": "Како миш, додирна табла и 3D миш померају приказ.",
"prefs.navigator_fit": "Уклопи модел након промене приказа у навигатору",
"prefs.navigator_fit_note": "Лице, угао или стрелица коцке приказа, односно оса гизма оријентације, такође усмерава поглед на средину модела са једног растојања на којем се уклапа из сваког смера (његова гранична сфера). Почетни приказ користи исти зум и центар док је ова опција укључена, па се прикази које изаберете после њега само окрећу. Искључено: приказ се окреће на месту и задржава свој циљ и зум.",
"prefs.network_host_remove": "Уклони",
"prefs.network_locations": "Дозволи мрежне локације у дизајнима",
"prefs.network_locations_note": "Искључено: повезане датотеке дизајна на другом рачунару (\\\\server\\share) отварају се само са сервера наведених овде или након што га дозволите када се то затражи.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Skapa ärende…",
"Cross curves": "Korskurvor",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsätter på GitHub.",
"Cube": "Kub",
"Current orthographic view (1:1 mm)": "Aktuell ortografisk vy (1:1 mm)",
"Current perspective view": "Aktuell perspektivvy",
"Current plane": "Aktuellt plan",
@@ -2240,6 +2241,9 @@
"prefs.interface_note": "Hur SolidCraft ser ut och var dess delar placeras.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertera de böjda rullningspilarna",
"prefs.invert_curved_roll_arrows_note": "De två böjda pilarna vid kubens hörn rullar vyn i skärmplanet. På: medurspilen rullar moturs och moturspilen rullar medurs. Av: varje pil rullar vyn åt det håll den kröker sig.",
"prefs.invert_navigator_arrows": "Invertera rotationspilarna på vykuben",
"prefs.invert_navigator_arrows_note": "Pilarna runt kuben orbiterar kameran åt det håll de pekar, som i Fusion och Inventor: pilen till vänster pekar åt höger och svänger kameran åt höger. Av: en pil roterar kuben mot den sida den sitter på, så den vänstra pilen svänger kameran åt vänster. De böjda rullningspilarna påverkas inte.",
"prefs.keep_work_on_tab_switch": "Behåll dialoger och verktyg öppna när du byter konstruktion",
"prefs.keep_work_on_tab_switch_note": "Varje konstruktionsflik behåller sin öppna dialog eller sitt öppna verktyg, med det du har valt och skrivit i den, och sin flik i menyfliksområdet. De finns kvar när du kommer tillbaka till konstruktionen. Av: att byta konstruktion avbryter dem och visar fliken Modell.",
"prefs.labels": "Etiketter",
@@ -2276,6 +2280,7 @@
"prefs.navigation": "Navigering",
"prefs.navigation_note": "Hur musen, styrplattan och 3D-musen flyttar vyn.",
"prefs.navigator_fit": "Anpassa modellen efter en vyändring i navigatorn",
"prefs.navigator_fit_note": "En yta, ett hörn eller en pil på vykuben, eller en axel på orienteringsgizmot, tittar också mot modellens mitt från det enda avstånd som får den att rymmas från alla sidor (dess begränsningssfär). Hem använder samma zoom och centrum medan detta är på, så vyer som väljs efteråt bara vrids. Av: vyn vrids på stället och behåller sitt mål och sin zoom.",
"prefs.network_host_remove": "Ta bort",
"prefs.network_locations": "Tillåt nätverksplatser i konstruktioner",
"prefs.network_locations_note": "Av: en konstruktions länkade filer på en annan dator (\\\\server\\share) öppnas bara från de servrar som listas här, eller efter att du tillåtit en när du tillfrågas.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Sorun Oluştur…",
"Cross curves": "Çapraz eğriler",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter ile GitHub'da devam edilir.",
"Cube": "Küp",
"Current orthographic view (1:1 mm)": "Geçerli ortografik görünüm (1:1 mm)",
"Current perspective view": "Geçerli perspektif görünüm",
"Current plane": "Geçerli düzlem",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "SolidCraft'ın nasıl göründüğü ve parçalarının nerede durduğu.",
"prefs.interval_minutes": "{n} dk",
"prefs.invert_curved_roll_arrows": "Eğri yuvarlanma oklarını ters çevir",
"prefs.invert_curved_roll_arrows_note": "Küpün köşesindeki iki eğri ok, görünümü ekran düzlemi içinde yuvarlar. Açık: saat yönündeki ok saat yönünün tersine, saat yönünün tersindeki ok saat yönünde yuvarlar. Kapalı: her ok görünümü kıvrıldığı yöne yuvarlar.",
"prefs.invert_navigator_arrows": "Görünüm küpünün döndürme oklarını ters çevir",
"prefs.invert_navigator_arrows_note": "Küpün çevresindeki oklar kamerayı gösterdikleri yönde döndürür, tıpkı Fusion ve Inventor'daki gibi: soldaki ok sağı gösterir ve kamerayı sağa savurur. Kapalı: bir ok küpü bulunduğu tarafa doğru döndürür, yani sol ok kamerayı sola savurur. Kıvrık yuvarlanma okları bundan etkilenmez.",
"prefs.keep_work_on_tab_switch": "Tasarımlar arasında geçerken diyalogları ve araçları açık tut",
"prefs.keep_work_on_tab_switch_note": "Her tasarım sekmesi, açık diyaloğunu veya aracını, içinde seçtiklerinizi ve yazdıklarınızı ve şerit sekmesini korur. Tasarıma döndüğünüzde yeniden oradadırlar. Kapalı: tasarımlar arasında geçmek bunları iptal eder ve Model sekmesini gösterir.",
"prefs.labels": "Etiketler",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Gezinme",
"prefs.navigation_note": "Farenin, trackpad'in ve 3B farenin görünümü nasıl hareket ettirdiği.",
"prefs.navigator_fit": "Gezgin görünümü değiştikten sonra modeli sığdır",
"prefs.navigator_fit_note": "Görünüm küpünün bir yüzü, köşesi veya oku ya da gizmonun bir ekseni, modelin ortasına da modeli her yönden sığdıran tek bir uzaklıktan (sınırlayıcı küresi) bakar. Bu açıkken Ana görünüm aynı yakınlaştırmayı ve merkezi kullanır; böylece sonrasında seçilen görünümler yalnızca döner. Kapalı: görünüm hedefini ve yakınlaştırmasını koruyarak yerinde döner.",
"prefs.network_host_remove": "Kaldır",
"prefs.network_locations": "Tasarımlarda ağ konumlarına izin ver",
"prefs.network_locations_note": "Kapalı: bir tasarımın başka bir bilgisayardaki bağlı dosyaları (\\\\server\\paylaşım) yalnızca burada listelenen sunuculardan veya sorulduğunda izin verdiklerinizden açılır.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Створити повідомлення про проблему…",
"Cross curves": "Поперечні криві",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter продовжує на GitHub.",
"Cube": "Куб",
"Current orthographic view (1:1 mm)": "Поточний ортографічний вид (1:1 mm)",
"Current perspective view": "Поточний перспективний вид",
"Current plane": "Поточна площина",
@@ -2651,6 +2652,9 @@
"prefs.interface_note": "Як виглядає SolidCraft і де розташовані його частини.",
"prefs.interval_minutes": "{n} хв",
"prefs.invert_curved_roll_arrows": "Інвертувати вигнуті стрілки обертання",
"prefs.invert_curved_roll_arrows_note": "Дві вигнуті стрілки в куті куба обертають вид у площині екрана. Увімкнено: стрілка за годинниковою стрілкою обертає проти годинникової, а стрілка проти годинникової — за годинниковою. Вимкнено: кожна стрілка обертає вид у напрямку свого завитку.",
"prefs.invert_navigator_arrows": "Інвертувати стрілки обертання куба виду",
"prefs.invert_navigator_arrows_note": "Стрілки навколо куба обертають камеру в той бік, куди вказують, як у Fusion та Inventor: стрілка ліворуч вказує праворуч і повертає камеру праворуч. Вимк.: стрілка обертає куб у той бік, де вона розташована, тож ліва стрілка повертає камеру ліворуч. Вигнуті стрілки крену не змінюються.",
"prefs.keep_unsaved_also_asks": "Усе одно запитувати під час закриття вкладки",
"prefs.keep_unsaved_also_asks_tip": "Коли це вимкнено, вкладка закривається без вікна браузера, щойно копія кожного незбереженого проєкту актуальна.",
"prefs.keep_unsaved_in_browser": "Зберігати незбережену роботу в цьому браузері",
@@ -2710,6 +2714,7 @@
"prefs.move_drag_highlights_tip": "Вимкнено: коли стрілки «Перемістити» тягнуть компонент, нічого під вказівником не підсвічується, що зберігає плавність великих збірок. Якщо показано переріз чи аналіз, підсвічування все одно працює, а деталь, яку тягнуть уздовж її з’єднань, ніколи його не вмикає.",
"prefs.navigation": "Навігація",
"prefs.navigation.axes_signed": "Осі",
"prefs.navigation.cube_compact": "Куб",
"prefs.navigation.device": "Пристрій",
"prefs.navigation.free": "Вільне",
"prefs.navigation.orbit_style": "Стиль обертання",
@@ -2717,6 +2722,7 @@
"prefs.navigation.turntable": "Поворотний стіл",
"prefs.navigation_note": "Як миша, трекпад і 3D-миша рухають вид.",
"prefs.navigator_fit": "Вміщувати модель після зміни виду в навігаторі",
"prefs.navigator_fit_note": "Грань, кут або стрілка куба виду чи вісь гізмо також дивляться на середину моделі з єдиної відстані, з якої її видно цілком з усіх боків (її обмежувальна сфера). «Головний вид» за ввімкненого параметра використовує той самий масштаб і центр, тож види, вибрані після нього, лише повертаються. Вимк.: вид повертається на місці, зберігаючи свою ціль і масштаб.",
"prefs.network_host_remove": "Вилучити",
"prefs.network_locations": "Дозволяти мережеві розташування в проєктах",
"prefs.network_locations_note": "Для організацій, які зберігають проєкти на файлових серверах. Вимкнено: лише дозволені вами сервери.",
+5 -3
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Tạo Issue…",
"Cross curves": "Đường cong giao cắt",
"Ctrl+Enter continues on GitHub.": "Nhấn Ctrl+Enter để tiếp tục trên GitHub.",
"Cube": "Khối lập phương",
"Current orthographic view (1:1 mm)": "Góc nhìn trực giao hiện tại (1:1 mm)",
"Current perspective view": "Góc nhìn phối cảnh hiện tại",
"Current plane": "Mặt phẳng hiện tại",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "Diện mạo của SolidCraft và cách bố trí các bảng điều khiển.",
"prefs.interval_minutes": "{n} phút",
"prefs.invert_curved_roll_arrows": "Đảo ngược mũi tên cuộn cong",
"prefs.invert_curved_roll_arrows_note": "Hai mũi tên cong ở góc bộ điều hướng cuộn khung nhìn trong mặt phẳng màn hình. Khi bật: mũi tên theo chiều kim đồng hồ cuộn ngược chiều kim đồng hồ và ngược lại. Khi tắt: mỗi mũi tên cuộn khung nhìn theo chiều cong của nó.",
"prefs.invert_curved_roll_arrows_note": "Hai mũi tên cong ở góc khối cuộn khung nhìn trong mặt phẳng màn hình. Khi bật: mũi tên theo chiều kim đồng hồ cuộn ngược chiều kim đồng hồ và ngược lại. Khi tắt: mỗi mũi tên cuộn khung nhìn theo chiều cong của nó.",
"prefs.invert_navigator_arrows": "Đảo ngược mũi tên xoay của khối điều hướng",
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh bộ điều hướng xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khung nhìn về phía chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh khối xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khối về phía cạnh chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
"prefs.keep_unsaved_also_asks": "Vẫn hỏi khi đóng thẻ",
"prefs.keep_unsaved_also_asks_tip": "Khi tắt, thẻ sẽ đóng mà không có hộp thoại của trình duyệt khi bản sao của mọi thiết kế chưa lưu đã được cập nhật.",
"prefs.keep_unsaved_in_browser": "Giữ công việc chưa lưu trong trình duyệt này",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Tắt: khi các mũi tên của Di chuyển kéo một thành phần, không có gì dưới con trỏ được tô sáng, nhờ đó các cụm lắp ráp lớn vẫn mượt. Khi đang hiện mặt cắt hoặc phân tích thì vẫn tô sáng như thường, và chi tiết được kéo dọc theo khớp nối không bao giờ tô sáng.",
"prefs.navigation": "Điều hướng góc nhìn",
"prefs.navigation.axes_signed": "Trục",
"prefs.navigation.cube_compact": "Khối lập phương",
"prefs.navigation.device": "Thiết bị",
"prefs.navigation.free": "Tự do",
"prefs.navigation.orbit_style": "Kiểu xoay",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "Bàn xoay",
"prefs.navigation_note": "Cách chuột, bàn di cảm ứng và chuột 3D di chuyển góc nhìn.",
"prefs.navigator_fit": "Khớp mô hình sau khi đổi góc nhìn bằng khối điều hướng",
"prefs.navigator_fit_note": "Nhấp vào một mặt, góc hoặc mũi tên của bộ điều hướng, hoặc một trục của gizmo, cũng nhìn vào tâm mô hình từ một khoảng cách duy nhất chứa trọn nó từ mọi phía (khối cầu bao). Khi bật, góc nhìn chuẩn (Home) dùng cùng mức thu phóng và tâm đó, nên các góc nhìn chọn sau chỉ xoay. Tắt: góc nhìn xoay tại chỗ, giữ nguyên điểm nhìn và mức thu phóng.",
"prefs.navigator_fit_note": "Nhấp vào một mặt, góc hoặc mũi tên của khối lập phương, hoặc một trục của gizmo, cũng nhìn vào tâm mô hình từ một khoảng cách duy nhất chứa trọn nó từ mọi phía (khối cầu bao). Khi bật, góc nhìn chuẩn (Home) dùng cùng mức thu phóng và tâm đó, nên các góc nhìn chọn sau chỉ xoay. Tắt: góc nhìn xoay tại chỗ, giữ nguyên điểm nhìn và mức thu phóng.",
"prefs.network_host_remove": "Xóa",
"prefs.network_locations": "Cho phép các vị trí mạng trong thiết kế",
"prefs.network_locations_note": "Dành cho tổ chức lưu thiết kế trên máy chủ tệp. Khi tắt: chỉ các máy chủ bạn cho phép.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "創建 Issue…",
"Cross curves": "交叉曲線",
"Ctrl+Enter continues on GitHub.": "按Ctrl+Enter在GitHub中繼續。",
"Cube": "立方體",
"Current orthographic view (1:1 mm)": "目前正交視圖(1:1毫米)",
"Current perspective view": "目前透視視圖",
"Current plane": "目前平面",
@@ -2248,6 +2249,9 @@
"prefs.interface_note": "SolidCraft 的外觀和面板佈局。",
"prefs.interval_minutes": "{n} 分鐘",
"prefs.invert_curved_roll_arrows": "反轉彎曲的滾轉箭頭",
"prefs.invert_curved_roll_arrows_note": "立方體角落的兩個彎曲箭頭會在螢幕平面內滾轉檢視。開啟時:順時針箭頭會逆時針滾轉,逆時針箭頭會順時針滾轉。關閉時:每個箭頭依其彎曲的方向滾轉檢視。",
"prefs.invert_navigator_arrows": "反轉檢視立方體的旋轉箭頭",
"prefs.invert_navigator_arrows_note": "立方體周圍的箭頭會依其所指方向環繞相機,與 Fusion 和 Inventor 相同:左側箭頭指向右方,並將相機向右擺動。關閉時:箭頭會將立方體轉向它所在的一側,因此左側箭頭會將相機向左擺動。彎曲的滾轉箭頭不受影響。",
"prefs.keep_work_on_tab_switch": "切換設計時保持對話方塊與工具開啟",
"prefs.keep_work_on_tab_switch_note": "每個設計分頁都會保留其開啟的對話方塊或工具、您在其中選取與輸入的內容,以及其工具列索引標籤。回到該設計時,它們會恢復原狀。關閉時:切換設計會取消它們,並顯示「模型」索引標籤。",
"prefs.labels": "標籤",
@@ -2284,6 +2288,7 @@
"prefs.navigation": "導航",
"prefs.navigation_note": "游標、觸控板和3D游標如何移動視圖。",
"prefs.navigator_fit": "變更導覽器檢視後使模型符合視圖",
"prefs.navigator_fit_note": "檢視立方體的面、角或箭頭,或方向控制器的某個軸,也會從能容納整個模型各側的單一距離(其邊界球)看向模型中心。啟用時,「主檢視」使用相同的縮放與中心,因此之後選擇的檢視只會旋轉。關閉時:檢視原地旋轉,保留其目標與縮放。",
"prefs.network_host_remove": "刪除",
"prefs.network_locations": "認可設計中的網絡位置",
"prefs.network_locations_note": "關閉:設計中位於其他計算機 (\\\\server\\share) 上的鏈接檔案,只會從此處列出的服務器開啟,或在詢問時你認可的服務器開啟。",
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "创建 Issue…",
"Cross curves": "交叉曲线",
"Ctrl+Enter continues on GitHub.": "按Ctrl+Enter在GitHub中继续。",
"Cube": "立方体",
"Current orthographic view (1:1 mm)": "当前正交视图(1:1毫米)",
"Current perspective view": "当前透视视图",
"Current plane": "当前平面",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "SolidCraft 的外观和面板布局。",
"prefs.interval_minutes": "{n} 分钟",
"prefs.invert_curved_roll_arrows": "反转弯曲的翻滚箭头",
"prefs.invert_curved_roll_arrows_note": "导航器角落的两个弯曲箭头在屏幕平面内翻滚视图。开启:顺时针箭头逆时针翻滚,逆时针箭头顺时针翻滚。关闭:每个箭头按其弯曲方向翻滚视图。",
"prefs.invert_navigator_arrows": "反转导航器的旋转箭头",
"prefs.invert_navigator_arrows_note": "导航器周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把视图转向它所在的那一侧,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
"prefs.invert_curved_roll_arrows_note": "立方体角落的两个弯曲箭头在屏幕平面内翻滚视图。开启:顺时针箭头逆时针翻滚,逆时针箭头顺时针翻滚。关闭:每个箭头按其弯曲方向翻滚视图。",
"prefs.invert_navigator_arrows": "反转视图立方体的旋转箭头",
"prefs.invert_navigator_arrows_note": "立方体周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把立方体转向它所在的那一面,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
"prefs.keep_unsaved_also_asks": "关闭标签页时仍然询问",
"prefs.keep_unsaved_also_asks_tip": "关闭此项后,只要每个未保存设计的副本都是最新的,标签页就会直接关闭,不显示浏览器的提示框。",
"prefs.keep_unsaved_in_browser": "在此浏览器中保留未保存的工作",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "关闭:用移动的箭头拖动组件时,不高亮指针下的对象,大型装配体也能保持流畅。显示剖切或分析时仍照常高亮;沿关节拖动零件时从不高亮。",
"prefs.navigation": "导航",
"prefs.navigation.axes_signed": "坐标轴",
"prefs.navigation.cube_compact": "立方体",
"prefs.navigation.device": "设备",
"prefs.navigation.free": "自由",
"prefs.navigation.orbit_style": "旋转方式",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "转台",
"prefs.navigation_note": "鼠标、触控板和3D鼠标如何移动视图。",
"prefs.navigator_fit": "视图导航器切换视图后适配模型",
"prefs.navigator_fit_note": "点击导航器的面、角或箭头,或坐标轴指示器的轴时,也会从各个方向都能容纳模型的同一距离(其包围球)注视模型中心。开启期间主视图使用相同的缩放和中心,因此之后选择的视图只改变方向。关闭:视图原地旋转,保持目标点和缩放。",
"prefs.navigator_fit_note": "点击立方体的面、角或箭头,或坐标轴指示器的轴时,也会从各个方向都能容纳模型的同一距离(其包围球)注视模型中心。开启期间主视图使用相同的缩放和中心,因此之后选择的视图只改变方向。关闭:视图原地旋转,保持目标点和缩放。",
"prefs.network_host_remove": "删除",
"prefs.network_locations": "允许设计中的网络位置",
"prefs.network_locations_note": "适用于将设计存放在文件服务器上的组织。关闭时:仅允许您授权的服务器。",
+4 -4
View File
@@ -39,10 +39,10 @@
],
"control_border": "#ffffff",
"control_fill": "#000000",
"navigator_border": "#ffffff",
"navigator_face": "#000000",
"navigator_hover": "#000000",
"navigator_text": "#ffffff",
"cube_border": "#ffffff",
"cube_face": "#000000",
"cube_hover": "#000000",
"cube_text": "#ffffff",
"dialog_bg": "#000000",
"dialog_body": "#000000",
"dialog_border": "#ffffff",
+4 -4
View File
@@ -39,10 +39,10 @@
],
"control_border": "#000000",
"control_fill": "#ffffff",
"navigator_border": "#000000",
"navigator_face": "#ffffff",
"navigator_hover": "#ffffff",
"navigator_text": "#000000",
"cube_border": "#000000",
"cube_face": "#ffffff",
"cube_hover": "#ffffff",
"cube_text": "#000000",
"dialog_bg": "#ffffff",
"dialog_body": "#ffffff",
"dialog_border": "#000000",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#d4d0ca",
"control_fill": "#fffdfa",
"navigator_border": "#b5b0a9",
"navigator_face": "#fffdfa",
"navigator_hover": "#d4d0ca",
"navigator_text": "#13110e",
"cube_border": "#b5b0a9",
"cube_face": "#fffdfa",
"cube_hover": "#d4d0ca",
"cube_text": "#13110e",
"dialog_bg": "#f9f6f2",
"dialog_body": "#f9f6f2",
"dialog_border": "#d4d0ca",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#533812",
"control_fill": "#1d1406",
"navigator_border": "#533812",
"navigator_face": "#36250c",
"navigator_hover": "#563a13",
"navigator_text": "#efa335",
"cube_border": "#533812",
"cube_face": "#36250c",
"cube_hover": "#563a13",
"cube_text": "#efa335",
"dialog_bg": "#100b04",
"dialog_body": "#1d1406",
"dialog_border": "#533812",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#315777",
"control_fill": "#112d4b",
"navigator_border": "#315777",
"navigator_face": "#163b60",
"navigator_hover": "#285f89",
"navigator_text": "#e3f0fa",
"cube_border": "#315777",
"cube_face": "#163b60",
"cube_hover": "#285f89",
"cube_text": "#e3f0fa",
"dialog_bg": "#0c223c",
"dialog_body": "#112d4b",
"dialog_border": "#315777",
@@ -42,10 +42,10 @@
],
"control_border": "#45475a",
"control_fill": "#313244",
"navigator_border": "#45475a",
"navigator_face": "#313244",
"navigator_hover": "#302b46",
"navigator_text": "#cdd6f4",
"cube_border": "#45475a",
"cube_face": "#313244",
"cube_hover": "#302b46",
"cube_text": "#cdd6f4",
"dialog_bg": "#1e1e2e",
"dialog_body": "#1e1e2e",
"dialog_border": "#45475a",
+4 -4
View File
@@ -39,10 +39,10 @@
],
"control_border": "#55ffff",
"control_fill": "#000000",
"navigator_border": "#55ffff",
"navigator_face": "#000000",
"navigator_hover": "#aa00aa",
"navigator_text": "#ffffff",
"cube_border": "#55ffff",
"cube_face": "#000000",
"cube_hover": "#aa00aa",
"cube_text": "#ffffff",
"dialog_bg": "#000000",
"dialog_body": "#000000",
"dialog_border": "#55ffff",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#5d5246",
"control_fill": "#3c352d",
"navigator_border": "#706354",
"navigator_face": "#3c352d",
"navigator_hover": "#5d5246",
"navigator_text": "#e4e1dd",
"cube_border": "#706354",
"cube_face": "#3c352d",
"cube_hover": "#5d5246",
"cube_text": "#e4e1dd",
"dialog_bg": "#312b25",
"dialog_body": "#312b25",
"dialog_border": "#4b4238",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#dcd3c2",
"control_fill": "#fdfaf3",
"navigator_border": "#b7b1a7",
"navigator_face": "#fdfaf3",
"navigator_hover": "#dcd3c2",
"navigator_text": "#14110d",
"cube_border": "#b7b1a7",
"cube_face": "#fdfaf3",
"cube_hover": "#dcd3c2",
"cube_text": "#14110d",
"dialog_bg": "#faf7f1",
"dialog_body": "#faf7f1",
"dialog_border": "#dcd3c2",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#b0b0b4",
"control_fill": "#ececec",
"navigator_border": "#9a9aa0",
"navigator_face": "#f2f2f4",
"navigator_hover": "#cce5ff",
"navigator_text": "#262628",
"cube_border": "#9a9aa0",
"cube_face": "#f2f2f4",
"cube_hover": "#cce5ff",
"cube_text": "#262628",
"dialog_bg": "#ececec",
"dialog_body": "#f3f3f3",
"dialog_border": "#c6c6c8",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#484d55",
"control_fill": "#303338",
"navigator_border": "#484d55",
"navigator_face": "#303338",
"navigator_hover": "#293c49",
"navigator_text": "#e0e2e5",
"cube_border": "#484d55",
"cube_face": "#303338",
"cube_hover": "#293c49",
"cube_text": "#e0e2e5",
"dialog_bg": "#25272b",
"dialog_body": "#25272b",
"dialog_border": "#484d55",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#285333",
"control_fill": "#0b1d10",
"navigator_border": "#285333",
"navigator_face": "#0f3617",
"navigator_hover": "#175625",
"navigator_text": "#40ee66",
"cube_border": "#285333",
"cube_face": "#0f3617",
"cube_hover": "#175625",
"cube_text": "#40ee66",
"dialog_bg": "#061009",
"dialog_body": "#0b1d10",
"dialog_border": "#285333",
+4 -4
View File
@@ -45,10 +45,10 @@
"preview_new": "#fabd2f",
"preview_sketch": "#b8bb26",
"preview_cut": "#fb49346e",
"navigator_face": "#ebdbb2",
"navigator_border": "#665c54",
"navigator_text": "#282828",
"navigator_hover": "#83a598",
"cube_face": "#ebdbb2",
"cube_border": "#665c54",
"cube_text": "#282828",
"cube_hover": "#83a598",
"viewport_top": "#32302f",
"viewport_bottom": "#32302f",
"grid": "#443f3c",
+4 -4
View File
@@ -44,10 +44,10 @@
"preview_new": "#d79921",
"preview_sketch": "#98971a",
"preview_cut": "#cc241d6e",
"navigator_face": "#fbf1c7",
"navigator_border": "#7c6f64",
"navigator_text": "#3c3836",
"navigator_hover": "#83a598",
"cube_face": "#fbf1c7",
"cube_border": "#7c6f64",
"cube_text": "#3c3836",
"cube_hover": "#83a598",
"viewport_top": "#fcf5d8",
"viewport_bottom": "#ebdbb2",
"grid": "#d5c4a1",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#a0a0a0",
"control_fill": "#151515",
"navigator_border": "#a0a0a0",
"navigator_face": "#151515",
"navigator_hover": "#002c45",
"navigator_text": "#ffffff",
"cube_border": "#a0a0a0",
"cube_face": "#151515",
"cube_hover": "#002c45",
"cube_text": "#ffffff",
"dialog_bg": "#0c0c0c",
"dialog_body": "#000000",
"dialog_border": "#a0a0a0",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#4c566a",
"control_fill": "#3b4252",
"navigator_border": "#4c566a",
"navigator_face": "#3b4252",
"navigator_hover": "#35495b",
"navigator_text": "#eceff4",
"cube_border": "#4c566a",
"cube_face": "#3b4252",
"cube_hover": "#35495b",
"cube_text": "#eceff4",
"dialog_bg": "#2e3440",
"dialog_body": "#2e3440",
"dialog_border": "#4c566a",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#50546d",
"control_fill": "#343746",
"navigator_border": "#50546d",
"navigator_face": "#343746",
"navigator_hover": "#393149",
"navigator_text": "#f8f8f2",
"cube_border": "#50546d",
"cube_face": "#343746",
"cube_hover": "#393149",
"cube_text": "#f8f8f2",
"dialog_bg": "#282a36",
"dialog_body": "#282a36",
"dialog_border": "#50546d",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#474b4f",
"control_fill": "#2c2e31",
"navigator_border": "#585b5f",
"navigator_face": "#2c2e31",
"navigator_hover": "#474b4f",
"navigator_text": "#e1e3e5",
"cube_border": "#585b5f",
"cube_face": "#2c2e31",
"cube_hover": "#474b4f",
"cube_text": "#e1e3e5",
"dialog_bg": "#222527",
"dialog_body": "#222527",
"dialog_border": "#383b3e",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#4a5262",
"control_fill": "#272b34",
"navigator_border": "#5c6370",
"navigator_face": "#abb2bf",
"navigator_hover": "#61afef",
"navigator_text": "#21252b",
"cube_border": "#5c6370",
"cube_face": "#abb2bf",
"cube_hover": "#61afef",
"cube_text": "#21252b",
"dialog_bg": "#282c34",
"dialog_body": "#3b4453",
"dialog_border": "#4b5263",
+6 -6
View File
@@ -38,10 +38,10 @@
],
"control_border": "#4a4f54",
"control_fill": "#303235",
"navigator_border": "#50565b",
"navigator_face": "#34373a",
"navigator_hover": "#53616c",
"navigator_text": "#dededc",
"cube_border": "#50565b",
"cube_face": "#34373a",
"cube_hover": "#53616c",
"cube_text": "#dededc",
"dialog_bg": "#2b2d2f",
"dialog_body": "#2b2d2f",
"dialog_border": "#3d4145",
@@ -451,7 +451,7 @@
"hover_profile": "#b7bdc230",
"origin_plane_hover": "#b7bdc260",
"profile_fill": "#b7bdc228",
"navigator_hover": "#454b50",
"cube_hover": "#454b50",
"chip": "#b7bdc2",
"logo": [
"#dde0e3",
@@ -498,7 +498,7 @@
"hover_profile": "#aabcae30",
"origin_plane_hover": "#aabcae60",
"profile_fill": "#aabcae28",
"navigator_hover": "#414d45",
"cube_hover": "#414d45",
"chip": "#aabcae",
"logo": [
"#d1ddd4",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#888888",
"control_fill": "#dddddd",
"navigator_border": "#888888",
"navigator_face": "#eeeeee",
"navigator_hover": "#ccccff",
"navigator_text": "#222222",
"cube_border": "#888888",
"cube_face": "#eeeeee",
"cube_hover": "#ccccff",
"cube_text": "#222222",
"dialog_bg": "#dddddd",
"dialog_body": "#eeeeee",
"dialog_border": "#888888",
+4 -4
View File
@@ -38,10 +38,10 @@
],
"control_border": "#586e75",
"control_fill": "#073642",
"navigator_border": "#586e75",
"navigator_face": "#073642",
"navigator_hover": "#586e75",
"navigator_text": "#93a1a1",
"cube_border": "#586e75",
"cube_face": "#073642",
"cube_hover": "#586e75",
"cube_text": "#93a1a1",
"dialog_bg": "#073642",
"dialog_body": "#073642",
"dialog_border": "#586e75",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#b6b3a1",
"control_fill": "#e3ddc9",
"navigator_border": "#b6b3a1",
"navigator_face": "#e3ddc9",
"navigator_hover": "#e1e8d9",
"navigator_text": "#586e75",
"cube_border": "#b6b3a1",
"cube_face": "#e3ddc9",
"cube_hover": "#e1e8d9",
"cube_text": "#586e75",
"dialog_bg": "#eee8d5",
"dialog_body": "#eee8d5",
"dialog_border": "#b6b3a1",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#808080",
"control_fill": "#c0c0c0",
"navigator_border": "#808080",
"navigator_face": "#c0c0c0",
"navigator_hover": "#8080ff",
"navigator_text": "#000000",
"cube_border": "#808080",
"cube_face": "#c0c0c0",
"cube_hover": "#8080ff",
"cube_text": "#000000",
"dialog_bg": "#c0c0c0",
"dialog_body": "#c0c0c0",
"dialog_border": "#808080",
+4 -4
View File
@@ -42,10 +42,10 @@
],
"control_border": "#414868",
"control_fill": "#24283b",
"navigator_border": "#414868",
"navigator_face": "#24283b",
"navigator_hover": "#253452",
"navigator_text": "#c0caf5",
"cube_border": "#414868",
"cube_face": "#24283b",
"cube_hover": "#253452",
"cube_text": "#c0caf5",
"dialog_bg": "#1a1b26",
"dialog_body": "#1a1b26",
"dialog_border": "#414868",
@@ -1 +0,0 @@
| assets/locales/lv.json | SolidCraft contributors | Original Latvian translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
+1 -1
View File
@@ -189,7 +189,7 @@ pub(crate) fn remap_link(
remap_link(a, ids, names, bodies, depth + 1);
remap_link(b, ids, names, bodies, depth + 1);
}
LinkSource::Plane { name } | LinkSource::ConstructionPoint { name } => mapped_name(name, names),
LinkSource::Plane { name } => mapped_name(name, names),
// A construction axis, by name (#9324); the origin axes are no feature's.
LinkSource::Axis { name } if !matches!(name.as_str(), "X" | "Y" | "Z") => mapped_name(name, names),
_ => {}
+1 -28
View File
@@ -300,34 +300,7 @@ impl Document {
matches!(source, Some(solidcraft_kernel::FaceSource::Imported { item: current_item, face: current_face, payload_sha256: Some(digest), producer: Some(producer) }) if current_item == item && current_face == face && digest == payload_sha256 && *producer == target.origin_feature).then_some(index)
}).collect();
if indices.is_empty() {
// A linked design's face is named after its name in that design (`link:…`, see
// lineage::link_role): Update Links brings in a new file, whose digest no
// certificate matches, but a face it left as it was keeps that name. Find it by
// the name, as joints on linked faces do (#3330); a face numbered by its place
// (`face:<k>`) is not followed, since another face may take that place.
let linked = crate::persistent_name::split_feature(&target.name)
.is_some_and(|(id, role)| id == target.origin_feature && role.starts_with("link:"));
let names = crate::naming::face_names(body);
let named: Vec<usize> = if linked {
names
.iter()
.enumerate()
.filter(|(index, name)| {
crate::naming::strip_piece(name) == target.name
&& matches!(
body.body.face_sources().and_then(|sources| sources.get(*index)),
Some(Some(solidcraft_kernel::FaceSource::Imported { producer: Some(producer), .. })) if *producer == target.origin_feature
)
})
.map(|(index, _)| index)
.collect()
} else {
Vec::new()
};
if named.is_empty() {
return Err(DocError::Unknown("immutable import face certificate no longer exists".into()));
}
return Ok(self.without_copies(body, named));
return Err(DocError::Unknown("immutable import face certificate no longer exists".into()));
}
return Ok(self.without_copies(body, indices));
}
+1 -2
View File
@@ -7,7 +7,6 @@
use serde::{Deserialize, Serialize};
pub use crate::tolerance::{DimensionStyle, DimensionText, DimensionValue, format_dimension};
use crate::{DocError, Result, expr};
/// Units per millimetre and the unit's name. Unknown names use millimetres.
@@ -276,7 +275,7 @@ fn round_decimal_step(x: f64, step: f64, decimals: u8, resolution: usize, ties:
round_prepared(&magnitude, x.is_sign_negative(), decimals, ties)
}
pub(crate) fn grouped_digits(text: &mut String, digits: &str, integer: bool, groups: bool) {
fn grouped_digits(text: &mut String, digits: &str, integer: bool, groups: bool) {
for (i, digit) in digits.chars().enumerate() {
if groups && digits.len() >= 5 && i > 0 && if integer { (digits.len() - i).is_multiple_of(3) } else { i.is_multiple_of(3) } {
text.push('\u{202f}');
+6 -52
View File
@@ -461,13 +461,8 @@ impl ThinSide {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AxisRef {
/// A line of a sketch. `sketch` names the sketch that owns the line (#6548); without it
/// the line is a line of the profile's sketch, the form saved before #6548.
SketchLine {
curve: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
sketch: Option<u64>,
},
/// A line of the profile's sketch.
SketchLine { curve: String },
/// Sketch x or y axis through the sketch origin (`x` / `y`).
SketchAxis { axis: String },
/// World X / Y / Z axis through the origin.
@@ -578,43 +573,19 @@ pub struct FlangeEdge {
pub angle: Option<Expr>,
#[walk(length = "Edge height")]
pub height: Option<Expr>,
/// The edge's segments (`sheet.flange`'s `segments`): one stretch of the edge each, with its
/// own angle, height and side. Empty: the whole edge, one bend.
pub segments: Vec<FlangeSegment>,
}
impl FlangeEdge {
/// An edge that takes the feature's angle and height.
pub fn at(point: Vec3) -> Self {
Self { point: Position(point), angle: None, height: None, segments: Vec::new() }
Self { point: Position(point), angle: None, height: None }
}
}
/// One segment of an edge flange's edge: a stretch of the edge as fractions of the stretch the
/// sheet still has (`from`, `to`, 0…1), with its own angle, height and side where given (the
/// edge's, then the feature's, where left out). See `sheet::SheetBody::add_flanges_each`.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(deny_unknown_fields)]
pub struct FlangeSegment {
pub from: f64,
pub to: f64,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(angle = "Segment angle")]
pub angle: Option<Expr>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(length = "Segment height")]
pub height: Option<Expr>,
/// This segment's side, where it has one of its own: it replaces the feature's `flip` outright
/// for this stretch rather than turning relative to it, so `Some(false)` is the default
/// direction and `Some(true)` the other one, whatever the feature's `flip` is.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub flip: Option<bool>,
}
impl Serialize for FlangeEdge {
fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
if self.angle.is_none() && self.height.is_none() && self.segments.is_empty() {
if self.angle.is_none() && self.height.is_none() {
return self.point.serialize(s);
}
let mut m = s.serialize_map(None)?;
@@ -625,9 +596,6 @@ impl Serialize for FlangeEdge {
if let Some(h) = &self.height {
m.serialize_entry("height", h)?;
}
if !self.segments.is_empty() {
m.serialize_entry("segments", &self.segments)?;
}
m.end()
}
}
@@ -644,21 +612,19 @@ impl<'de> Deserialize<'de> for FlangeEdge {
angle: Option<Expr>,
#[serde(default)]
height: Option<Expr>,
#[serde(default)]
segments: Vec<FlangeSegment>,
}
struct Edge;
impl<'de> serde::de::Visitor<'de> for Edge {
type Value = FlangeEdge;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a point [x, y, z] or an edge {point, angle?, height?, segments?}")
f.write_str("a point [x, y, z] or an edge {point, angle?, height?}")
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(self, seq: A) -> std::result::Result<FlangeEdge, A::Error> {
Vec3::deserialize(SeqAccessDeserializer::new(seq)).map(FlangeEdge::at)
}
fn visit_map<A: serde::de::MapAccess<'de>>(self, map: A) -> std::result::Result<FlangeEdge, A::Error> {
let o = Own::deserialize(MapAccessDeserializer::new(map))?;
Ok(FlangeEdge { point: Position(o.point), angle: o.angle, height: o.height, segments: o.segments })
Ok(FlangeEdge { point: Position(o.point), angle: o.angle, height: o.height })
}
}
d.deserialize_any(Edge)
@@ -4484,18 +4450,6 @@ impl Document {
name
}
/// Create a model parameter with a name the caller chose (checked: valid and free).
pub fn new_named_model_param(&mut self, name: &str, expr_s: &str, unit: &str) -> Result<String> {
if let Some(why) = Self::param_name_problem(name) {
return Err(DocError::Invalid(why));
}
if self.name_taken(name) {
return Err(DocError::Invalid(format!("there is already a parameter `{name}`")));
}
self.params.push(Param { name: name.into(), expr: expr_s.into(), unit: unit.into(), comment: String::new(), model: true });
Ok(name.into())
}
/// Evaluate an expression against the document's parameters.
pub fn eval(&self, e: &str, kind: Kind) -> Result<f64> {
// The parameters are evaluated only when the expression names one: most expressions an
+10 -95
View File
@@ -1761,14 +1761,6 @@ impl PlacementReads {
self.link(doc, st, b);
}
// In the sketch's own frame: the component's origin, axes and planes, its own axes, text.
// A construction point is kept in its own component's frame: the sketch reads where
// that component is placed (#12075).
L::ConstructionPoint { name } => match doc.find_feature(name) {
Some(point) => {
self.components.insert(point.component);
}
None => self.all = true,
},
L::Origin | L::Axis { .. } | L::SketchAxis { .. } | L::Plane { .. } | L::Text { .. } => {}
}
}
@@ -4641,19 +4633,16 @@ fn naming_feature<'a>(vals: &BTreeMap<String, Value>, f: &'a Feature) -> std::bo
/// The revolve axis in the sketch's plane coordinates (a point and a direction). `st` is the model
/// an axis on an edge or face of it is found in; `construct` gives a construction axis, by name, in
/// the sketch's 3D frame; `vals` are the parameter values an explicit axis's origin is read with;
/// `sketch_line` gives a line of another sketch, by owning sketch feature and curve id, in the
/// same frame as `ss` (#6548).
/// the sketch's 3D frame; `vals` are the parameter values an explicit axis's origin is read with.
pub(crate) fn revolve_axis(
vals: &BTreeMap<String, Value>,
ss: &SolvedSketch,
axis: &AxisRef,
st: &ModelState,
construct: &dyn Fn(&str) -> Result<(Vec3, Vec3)>,
sketch_line: &dyn Fn(u64, &str) -> Result<(Vec3, Vec3)>,
) -> Result<(Vec2, Vec2)> {
match axis {
AxisRef::SketchLine { curve, sketch: None } => {
AxisRef::SketchLine { curve } => {
let ci = ss.sketch.curve_index(curve).ok_or_else(|| DocError::Unknown(format!("sketch line `{curve}`")))?;
match ss.sketch.curves.get(ci).map(|c| &c.kind) {
Some(CurveKind::Line { a, b }) => {
@@ -4663,10 +4652,6 @@ pub(crate) fn revolve_axis(
_ => Err(DocError::Invalid(format!("`{curve}` is not a line"))),
}
}
AxisRef::SketchLine { curve, sketch: Some(owner) } => {
let (o, d) = sketch_line(*owner, curve)?;
line_in_sketch_plane(ss, o, d)
}
AxisRef::SketchAxis { axis } => match axis.to_ascii_lowercase().as_str() {
"x" => Ok((Vec2::ZERO, Vec2::X)),
"y" => Ok((Vec2::ZERO, Vec2::Y)),
@@ -4697,19 +4682,6 @@ pub(crate) fn revolve_axis(
}
}
/// The line `curve` of a solved sketch, as a world-space point and direction in the sketch's
/// plane frame. Used to carry a revolve axis picked in another sketch (#6548).
pub(crate) fn sketch_line_world(ss: &SolvedSketch, curve: &str) -> Result<(Vec3, Vec3)> {
let ci = ss.sketch.curve_index(curve).ok_or_else(|| DocError::Unknown(format!("sketch line `{curve}`")))?;
match ss.sketch.curves.get(ci).map(|c| &c.kind) {
Some(CurveKind::Line { a, b }) => {
let (pa, pb) = (ss.sketch.point(*a).unwrap_or_default(), ss.sketch.point(*b).unwrap_or_default());
Ok((ss.plane.to_world(pa), ss.plane.dir_to_world(pb - pa)))
}
_ => Err(DocError::Invalid(format!("`{curve}` is not a line"))),
}
}
/// The model a revolve axis is found in: what construction geometry of component `comp` is built
/// on when the axis is an edge or face of it (only then is it worth placing); a model that cannot
/// be placed is the error.
@@ -4731,33 +4703,6 @@ fn line_in_sketch_plane(ss: &SolvedSketch, origin: Vec3, dir: Vec3) -> Result<(V
Ok((pl.to_local(origin), Vec2::new(d.dot(pl.x), d.dot(pl.y))))
}
/// A construction point `name` of the timeline so far, as evaluated, in the frame `frame` places
/// in the world: the frame a sketch is evaluated in, its component's placement or the placement
/// of the face it is attached to (#12075). The point is kept in its own component's frame.
pub(crate) fn construction_point_in(doc: &Document, st: &ModelState, name: &str, author: u64, frame: &Mat) -> Result<Vec3> {
let c = st
.construct
.iter()
.find(|c| c.name == name)
.ok_or_else(|| DocError::Unknown(format!("construction point `{name}` (it must come earlier in the timeline)")))?;
let crate::construct::ConstructGeom::Point(p) = &c.geom else {
return Err(DocError::Invalid(format!("`{name}` is not a construction point")));
};
if doc.occurrences.is_empty() {
return Ok(*p);
}
let owner = doc.feature(c.feature).map_or(0, |f| f.component);
// The same definition is authored in this occurrence, even when it is not the first.
// Its point is already in the author coordinates; using the first occurrence here
// would introduce the difference between the two placements.
if owner == author {
return Ok(*p);
}
let inverse = crate::mat_inverse(frame).ok_or_else(|| DocError::Invalid("the sketch's frame cannot be inverted".into()))?;
let relative = crate::mat_mul(&inverse, &doc.component_transform(owner));
Ok(crate::apply_point(&relative, *p))
}
/// A construction axis `name` of the timeline so far, as evaluated, in the frame of component
/// `comp`: a point on it and its direction. Without a document (`doc` None) it is taken in its
/// own component's frame.
@@ -5845,18 +5790,9 @@ fn feature_tools_with_constructor(
f,
)?;
let regions = solidcraft_sketch::merge_regions(&select_profiles(&ss, profiles)?);
let (o, d) = revolve_axis(
vals,
&ss,
axis,
&*axis_state(doc, st, f.component, axis)?,
&|name| construction_axis_in(Some(doc), st, name, f.component),
&|owner, curve| {
let solved =
st.sketch(owner).ok_or_else(|| DocError::Unknown(format!("sketch {owner} (it must come earlier in the timeline)")))?;
sketch_line_world(&sketch_in_feature_frame(doc, solved, f.component)?, curve)
},
)?;
let (o, d) = revolve_axis(vals, &ss, axis, &*axis_state(doc, st, f.component, axis)?, &|name| {
construction_axis_in(Some(doc), st, name, f.component)
})?;
// To Object is in this feature's component frame: the model as seen from there.
let tst = if to.is_some() { state_in_frame(doc, st, f.component)? } else { std::borrow::Cow::Borrowed(st) };
let angles = if to.is_some() {
@@ -7146,10 +7082,6 @@ fn replay(
kept.dedup();
let (mut missed, mut total) = (0usize, 0usize);
let plan = copy_plan(doc, vals, st, &kept, mats)?;
// A source's named faces are looked up in the model as it was before any copy was made: the
// copy of an earlier source (a boss joined to the body) changes the faces a later source (a cut
// starting on the boss) names, though the later source means the original's (#11792).
let named_from = plan.iter().any(|(src, _, _)| src.face_names.iter().any(|n| !n.is_empty())).then(|| st.clone());
for (src, mats, first) in &plan {
// A fillet or chamfer repeats at the copied edges.
if let FeatureKind::Fillet { edges, radius, .. } | FeatureKind::Chamfer { edges, distance: radius, .. } = &src.kind {
@@ -7195,21 +7127,6 @@ fn replay(
}
continue;
}
// An Offset Face repeats at the copied faces of the body they lie on.
if let FeatureKind::OffsetFace { faces, distance, body } = &src.kind {
let d = val(vals, distance, Kind::Length)?;
let picked = crate::plain(faces);
for m in mats {
let moved: Vec<Vec3> = picked.iter().map(|p| crate::apply_point(m, *p)).collect();
let i = body_at(st, body, &moved)?;
let Some(mb) = st.bodies.get(i).cloned() else { return Err(DocError::Invalid("body".into())) };
let nb = mb.traced().then(kernel::offset_faces(&mb.body, &moved, d)?);
if let Some(slot) = st.bodies.get_mut(i) {
*slot = ModelBody::traced_new(mb.name, nb, mb.feature);
}
}
continue;
}
// A moved copy is copied again as a body: each instance is the copy the Move made,
// placed by the pattern (#5931).
if let FeatureKind::Move { copy: true, .. } = &src.kind {
@@ -7304,7 +7221,7 @@ fn replay(
// Each copy's faces are named as the source feature's, with the instance. Its face
// points follow their named faces, as the feature's own did (#2121): a To Object
// extrude's copies reach the face where it is now, not where it was picked.
let moved = with_named_face_points(doc, named_from.as_ref().unwrap_or(st), src)?.map(|(g, _)| g);
let moved = with_named_face_points(doc, st, src)?.map(|(g, _)| g);
let tools = feature_tools_with_constructor(doc, vals, moved.as_ref().unwrap_or(src), st, &mut None, &mut None, &mut None)?;
for (k, m) in mats.iter().enumerate() {
let start = copies.len();
@@ -8713,13 +8630,11 @@ fn eval_sketch(
// A text's outlines are rebuilt from its numbers when the links are refreshed: the
// ones its expressions give come first.
doc.apply_text_values(vals, &mut sk)?;
// The frame the sketch is evaluated in, where a construction point it projects is
// brought from its own component's (#12075).
let link_frame = match anchor.map(|anchor| anchor.author_frame(doc, f.component)) {
Some(Ok(frame)) => frame,
_ => doc.component_transform(f.component),
let mut warns = match (anchor, lost_names) {
(Some(anchor), crate::project::LostNames::Fail) => crate::project::refresh_face_anchor_links(doc, vals, &fst, &plane, &mut sk, anchor)?,
(None, crate::project::LostNames::Fail) => crate::project::refresh_links(doc, vals, &fst, &plane, &mut sk)?,
(anchor, crate::project::LostNames::Mark) => crate::project::refresh_links_marking_lost(doc, vals, &fst, &plane, &mut sk, anchor)?,
};
let mut warns = crate::project::refresh_links_with(doc, vals, &fst, &plane, &mut sk, anchor, lost_names, Some(&(f.component, link_frame)))?;
drop(fst);
sk.refresh_offsets()?;
if let Some(w) = face_warning {
+6 -130
View File
@@ -654,135 +654,11 @@ pub(super) fn sheet_eval(
return Err(DocError::Invalid("refold the sheet before adding flanges".into()));
}
let points: Vec<Vec3> = edges.iter().map(|e| e.point.0).collect();
let picks = sheet_picks(sh, f, &points, warning);
let mut each = Vec::with_capacity(edges.len());
for (k, (e, pick)) in edges.iter().zip(picks).enumerate() {
let (height, angle) = own.get(k).copied().unwrap_or((h, a));
if e.segments.is_empty() {
each.push(sheet::EdgeFlange::at(pick, height, angle, from));
continue;
}
// A segmented edge makes one flange per run of segments that share an angle, a
// height and a side: the same bend carries on (see `add_flanges_each`).
//
// The invariant the runs keep: the first starts at the edge's start (0), the last
// ends at its end (1), and each starts where the run before it ends, so the runs
// are sorted, contiguous and non-overlapping and every accepted stretch is covered.
let (edge_height, edge_angle) = (height, angle);
let mut runs: Vec<(f64, f64, f64, f64, bool)> = Vec::new();
// The end of the edge the runs made so far cover. A run starts here, never before
// it, so the runs are sorted, contiguous and non-overlapping by construction, and
// every accepted stretch's coverage is preserved up to the junction tolerance.
let mut covered = sheet::WHOLE_EDGE.0;
// The `to` of the segment before, as stored: the stretches must tile the edge, and
// a stored list that does not is refused here rather than built past the edge or
// with part of it left bare.
let mut prev_to = sheet::WHOLE_EDGE.0;
for (j, seg) in e.segments.iter().enumerate() {
if !(0.0..=1.0).contains(&seg.from) {
return Err(DocError::Invalid(format!("edges[{k}].segments[{j}].from must be a fraction from 0 to 1")));
}
if !(0.0..=1.0).contains(&seg.to) {
return Err(DocError::Invalid(format!("edges[{k}].segments[{j}].to must be a fraction from 0 to 1")));
}
if j == 0 && seg.from > sheet::SEGMENT_JOIN_EPS {
return Err(DocError::Invalid(format!("edges[{k}].segments[0].from must be 0: the segments cover the whole edge")));
}
if j > 0 && (seg.from - prev_to).abs() > sheet::SEGMENT_JOIN_EPS {
return Err(DocError::Invalid(format!(
"edges[{k}].segments[{j}].from must equal the to of the segment before it (the segments must meet, with no gap or overlap)"
)));
}
prev_to = seg.to;
let height = match &seg.height {
Some(x) => val(vals, x, Kind::Length)?,
None => height,
};
let angle = match &seg.angle {
Some(x) => val(vals, x, Kind::Angle)?,
None => angle,
};
// A segment's own angle and height are checked here, where its index is known,
// so a refusal names the segment the caller wrote.
if !(angle > 1e-6 && angle <= std::f64::consts::PI - 1e-6) {
return Err(DocError::Invalid(format!("edges[{k}].segments[{j}]: the flange angle must be between 0 and 180°")));
}
let least = from.before_leg(angle, rr, sh.t);
if !(height >= least - 1e-9) {
return Err(DocError::Invalid(format!(
"edges[{k}].segments[{j}]: the flange height must be at least {least:.3} mm for this bend"
)));
}
let side = seg.flip.unwrap_or(*flip);
// A junction the command accepts is one the build snaps shut, whether the two
// stretches match or not: the next stretch starts where the edge is covered, so
// no interior gap of the junction tolerance reaches trimming or the flat pattern
// and no run starts before the run before it ends. The 1e-12 comparison only
// says whether they are the same bend.
let start = seg.from.max(covered);
// Snapping the start to the covered end closes a tolerated gap or overlap.
let start = if start <= covered + sheet::SEGMENT_JOIN_EPS { covered } else { start };
if seg.to - start <= sheet::SEGMENT_JOIN_EPS {
// The stretch cannot be a bend of its own: it is narrower than the junction
// tolerance once the run before it is snapped to it, or it ends behind the
// covered end because it moves backwards across the junction. The run before
// it absorbs the stretch instead, its end moving on to the stretch's end but
// never backwards, so the edge stays covered from the first stretch to the
// last and no interval is left out of trimming or the flat pattern (the
// sliver's own angle and height do not build). A stretch absorbed before any
// run exists is covered by the run that follows it, which starts at the
// edge's start. Every span the build makes then runs forwards, so none
// reaches trimming or the flat pattern reversed.
covered = covered.max(seg.to);
if let Some(last) = runs.last_mut() {
last.1 = covered;
}
continue;
}
let same_bend =
runs.last().is_some_and(|last| (last.2 - height).abs() < 1e-12 && (last.3 - angle).abs() < 1e-12 && last.4 == side);
if same_bend {
// The same bend carries on: the junction closes and the run takes the
// stretch's end.
if let Some(last) = runs.last_mut() {
last.1 = seg.to;
}
} else {
// Another bend starts at the covered end, where the run before it ends. The
// first run starts at the edge's start however much `covered` has advanced
// over stretches absorbed before it: those stretches cannot be bends of
// their own, so this run covers them and the edge is covered from 0.
let start = if runs.is_empty() { sheet::WHOLE_EDGE.0 } else { start };
runs.push((start, seg.to, height, angle, side));
}
covered = seg.to;
}
if !runs.is_empty() && prev_to < sheet::WHOLE_EDGE.1 - sheet::SEGMENT_JOIN_EPS {
// A stored list that stops short of the edge's end leaves part of the edge
// without a flange; the command refuses it, so the build does too. A list of
// slivers only is the exception below: it builds the edge whole.
let n = e.segments.len() - 1;
return Err(DocError::Invalid(format!("edges[{k}].segments[{n}].to must be 1: the segments cover the whole edge")));
}
if runs.is_empty() {
// A list every stretch of which is absorbed cannot be written through
// `sheet.flange` (its last `to` must reach the edge's end), but a stored design
// can hold one: the edge still builds whole, as the feature's own bend, rather
// than losing its flange.
runs.push((sheet::WHOLE_EDGE.0, sheet::WHOLE_EDGE.1, edge_height, edge_angle, *flip));
}
// The command accepts a last `to` within the junction tolerance of the edge's end;
// the end itself is what builds, so snap it, as a merged run snaps the junctions it
// spans away.
if let Some(last) = runs.last_mut()
&& (last.1 - sheet::WHOLE_EDGE.1).abs() <= sheet::SEGMENT_JOIN_EPS
{
last.1 = sheet::WHOLE_EDGE.1;
}
for (span_from, span_to, height, angle, side) in runs {
each.push(sheet::EdgeFlange { pick, height, angle, from, span: (span_from, span_to), flip: Some(side) });
}
}
let each: Vec<sheet::EdgeFlange> = sheet_picks(sh, f, &points, warning)
.into_iter()
.zip(own)
.map(|(pick, (height, angle))| sheet::EdgeFlange { pick, height, angle, from })
.collect();
let n0 = sh.flanges.len();
let (_, notes) = sh.add_flanges_each(&each, rr, position, *flip, relief)?;
if !notes.is_empty() {
@@ -1751,7 +1627,7 @@ fn sheet_prism_cut(
}
}
let candidates = if sh.flat {
if sh.frame.normal().cross(n).len() > 1e-6 { Vec::new() } else { sh.flat_material()?.into_iter().map(|r| (None, r)).collect() }
if sh.frame.normal().cross(n).len() > 1e-6 { Vec::new() } else { sh.flat_regions()?.into_iter().map(|r| (None, r)).collect() }
} else {
sh.material_panels(Some(plane), &mut work)?
};
+3 -12
View File
@@ -311,18 +311,9 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
st.sketch(sketch.0).ok_or_else(|| DocError::Unknown(format!("sketch {sketch} (it must come earlier in the timeline)")))?,
f.component,
)?;
let (o, d) = revolve_axis(
vals,
&ss,
axis,
&*super::axis_state(doc, st, f.component, axis)?,
&|name| construction_axis_in(Some(doc), st, name, f.component),
&|owner, curve| {
let solved =
st.sketch(owner).ok_or_else(|| DocError::Unknown(format!("sketch {owner} (it must come earlier in the timeline)")))?;
sketch_line_world(&sketch_in_feature_frame(doc, solved, f.component)?, curve)
},
)?;
let (o, d) = revolve_axis(vals, &ss, axis, &*super::axis_state(doc, st, f.component, axis)?, &|name| {
construction_axis_in(Some(doc), st, name, f.component)
})?;
let a = val(vals, angle, Kind::Angle)?;
let (start, sweep) = match (angle2, symmetric) {
(Some(a2), _) => {
+2 -57
View File
@@ -130,57 +130,6 @@ impl Document {
self.resolve_attached_plane_noted(vals, plane, author, state, framed).map(|(plane, _)| plane)
}
/// A sketch attached by 0.30.1 to the cap of an extrude (an `extrude_cap` certificate), whose
/// cap the SMLib kernel no longer marks as that extrude's after a join (#13323): the attachment
/// also stores the cap's history name, a point on it and the plane the sketch was in. The sketch
/// keeps that plane when exactly that face is still there: the name finds the face, made by
/// the extrude the certificate names, on a body whose certified cap is nowhere else, a saved
/// point lies on it, and it still lies in the saved plane. A moved or edited face stays lost.
fn old_cap_plane(
&self,
anchor: &FaceAnchor,
name: Option<&str>,
at: solidcore_record::Vec3,
saved: &Plane,
state: &ModelState,
) -> Option<(Plane, Option<String>)> {
let target = &anchor.target;
let Some(crate::config::FaceCertificate::ExtrudeCap { sketch, high, outer, holes }) = &target.certificate else { return None };
if !anchor.path.is_empty() || !anchor.author_path.is_empty() || anchor.placement.is_some() {
return None;
}
let name = name.filter(|n| crate::persistent_name::made_by(crate::naming::strip_piece(n)) == Some(target.origin_feature))?;
let body = state.body(&target.body)?;
let solid = self.feature(target.origin_feature).is_some_and(|f| matches!(f.kind, FeatureKind::Extrude { thin: None, .. }));
if !solid || body.body.is_mesh() || body.definition_name() != target.body || !at.is_finite() {
return None;
}
// The checks below compare the body as built, before its offset: an offset body stays lost.
if self.model_body_offset(body).is_some_and(|offset| *offset != crate::IDENTITY) {
return None;
}
// The certified cap must be gone: while some body still has it, the attachment is exact.
let certified = |source: &Option<solidcraft_kernel::FaceSource>| {
matches!(source, Some(solidcraft_kernel::FaceSource::CertifiedExtrudeCap { producer, sketch: from, high: end, outer: around, holes: inside, .. })
if *producer == target.origin_feature && from == sketch && end == high && around == outer && inside == holes)
};
if state.bodies.iter().any(|other| other.body.face_sources().is_some_and(|sources| sources.iter().any(certified))) {
return None;
}
let indices = self.lineage_face_indices(body, name).ok()?;
let tolerance = (body.body.size() * 1e-6).max(1e-6);
let same_plane = |index: usize| {
body.body.planar_face(index).is_some_and(|face| {
face.normal().dot(saved.normal()) > 1. - 1e-8 && (face.origin - saved.origin).dot(saved.normal()).abs() <= tolerance
})
};
if indices.is_empty() || !indices.iter().all(|index| same_plane(*index)) || !crate::name_lookup::locate_on(body, name, at)?.on_point {
return None;
}
let note = format!("the face this sketch sits on was found again by its name `{name}`: its extrude-cap certificate no longer marks it");
Some((*saved, Some(note)))
}
/// [`Document::resolve_attached_plane`] with the note of an attachment found by fallback
/// ([`Document::anchored_face_indices`]).
pub fn resolve_attached_plane_noted(
@@ -196,12 +145,8 @@ impl Document {
return Err(DocError::Invalid("attached plane nesting exceeds budget".into()));
}
match plane {
PlaneRef::Face { anchor: Some(anchor), name, at, plane: saved } => {
let found = match doc.resolve_face_anchor_noted(anchor, author, state) {
Ok(found) => found,
Err(error) => doc.old_cap_plane(anchor, name.as_deref(), *at, saved, state).ok_or(error)?,
};
let (resolved, note) = found;
PlaneRef::Face { anchor: Some(anchor), .. } => {
let (resolved, note) = doc.resolve_face_anchor_noted(anchor, author, state)?;
*plane = PlaneRef::Custom { plane: resolved };
Ok(note)
}
@@ -1,5 +0,0 @@
//! `AxisRef::SketchLine` gains an optional `sketch`: the feature id of the sketch that owns the
//! axis line, so a revolve axis picked in another sketch resolves there instead of in the
//! profile sketch (#6548). Designs saved before this omit the field; they read unchanged and
//! keep resolving the line in the profile sketch, exactly as before. A design saved with it
//! carries the newer format number, which the last release refuses.
@@ -1,5 +0,0 @@
//! An edge flange saves `segments` on an edge (`{point, angle?, height?, segments}`), one stretch
//! of the edge each (`{from, to, angle?, height?, flip?}`), when `sheet.flange` was asked to split
//! the edge. Absent, an edge is the whole edge with one bend, as designs before this change were
//! built. An older design has none and keeps its flanges whole. The last release refuses a design
//! with this change (the newer format number).
@@ -1,6 +0,0 @@
//! A sketch link can save a named construction point as its source
//! (`{"type": "construction_point", "name": "Point1"}`): Project makes a linked point where the
//! construction point projects onto the sketch plane, and the point follows it (#12075). An older
//! design has no such link and opens as before. The last release opens a design that has one with
//! a warning about the newer format, keeps the sketch it can't read in its place on the timeline,
//! and saves it back as it came (`crates/doc/src/newer_file.rs`).
+5 -48
View File
@@ -571,26 +571,13 @@ pub(crate) fn matches(names: &Names, index: usize, name: &str) -> Option<Match>
if descends(current, name) {
return Some(Match::Piece);
}
// The named piece, told apart by the faces around it: they still bound this piece, directly or
// through a blend that replaced the edge it shared with them (`F4:blend:A|B` rounds the edge
// between A and B, and is named after it, so it still tells them apart). Or the face it was a
// piece of, whole again since, which they still bound: the piece is all of it (#11731). Only a
// piece told apart by faces: a numbered one (`#2`, nothing told it apart) says nothing about
// which part of the whole face it was.
// The named piece, told apart by the faces around it: they still bound this piece. Or the
// face it was a piece of, whole again since, which they still bound: the piece is all of it
// (#11731). Only a piece told apart by faces: a numbered one (`#2`, nothing told it apart)
// says nothing about which part of the whole face it was.
if let Some((stem, around)) = crate::piece_names::piece_parts(name)
&& (crate::naming::parent_piece(current) == Some(stem) || (current == stem && !around.is_empty() && name.ends_with(']')))
&& info.is_some_and(|i| around.iter().all(|f| i.bounds.contains(*f) || i.bounds.iter().any(|bound| rounds_the_edge(bound, current, f))))
{
return Some(Match::Piece);
}
// A piece of a blend face: a blend is named after the edge it replaced, so the qualifier that
// tells its pieces apart sits *inside* that name, on one of the edge's sides
// (`F4:blend:F2:side:c1#[F2:side:l3]|F2:side:l3`), and the face whole again since is the blend
// of the sides without their qualifiers (#4325).
if name.contains(":blend:")
&& let Some((stem, around)) = blend_piece(name)
&& (current == stem || crate::naming::parent_piece(current) == Some(stem.as_str()))
&& info.is_some_and(|i| around.iter().all(|f| i.bounds.contains(*f) || i.bounds.iter().any(|bound| rounds_the_edge(bound, &stem, f))))
&& info.is_some_and(|i| around.iter().all(|f| i.bounds.contains(*f)))
{
return Some(Match::Piece);
}
@@ -598,36 +585,6 @@ pub(crate) fn matches(names: &Names, index: usize, name: &str) -> Option<Match>
(crate::naming::strip_piece(current) == root).then_some(Match::Stem)
}
/// A piece of a blend face, read out of its name: the blend of the edge's sides without their
/// qualifiers (the face whole again since), and the faces that told the piece apart. `None` when no
/// side of the edge holds a qualifier, or the name is not a blend's.
fn blend_piece(name: &str) -> Option<(String, Vec<&str>)> {
let (a, b) = crate::naming::blend_sides(name)?;
let mut around = Vec::new();
for side in [a, b] {
if let Some((_, faces)) = crate::piece_names::piece_parts(side) {
around.extend(faces);
}
}
if around.is_empty() {
return None;
}
let mark = name.find(":blend:")?;
let stem = format!("{}:blend:{}|{}", name.get(..mark)?, crate::naming::strip_piece(a), crate::naming::strip_piece(b));
Some((stem, around))
}
/// Whether the face named `bound` (one of the faces around face `here`) is a blend that rounds the
/// edge `here` shared with face `face`: a fillet or chamfer sits between the two, so they no longer
/// touch, and the blend's name — the edge it replaced, `F4:blend:<here>|<face>` — is what tells them
/// apart now.
fn rounds_the_edge(bound: &str, here: &str, face: &str) -> bool {
let here = crate::naming::strip_piece(here);
let face = crate::naming::strip_piece(face);
let sides = |n: &str| crate::naming::strip_piece(n).to_string();
crate::naming::blend_sides(bound).is_some_and(|(a, b)| (sides(a) == here && sides(b) == face) || (sides(a) == face && sides(b) == here))
}
/// A name and the pattern instances after it (`F3:top#[F4:side]@F9.1` is `F3:top#[F4:side]` and
/// `@F9.1`; a copy of a copy carries one instance after another).
fn instance_suffix(n: &str) -> (&str, &str) {
-67
View File
@@ -189,70 +189,3 @@ fn a_piece_name_finds_its_face_once_it_is_whole_again() {
assert_eq!(matches(&names, 0, "top#[left]#2"), Some(Match::Stem));
assert_eq!(matches(&names, 0, "top#[]"), Some(Match::Stem));
}
/// A fillet or chamfer replaces the edge between two faces with a face of its own, named after
/// that edge (`F3:blend:side|start`): the two no longer touch, and the blend is what tells a piece
/// of one from a piece of another. A piece told apart by the face the blend separated from is
/// still found, so the edge saved with it is too (#4325).
#[test]
fn a_piece_name_survives_the_blend_that_replaced_the_edge_it_was_told_apart_by() {
// The side now meets the start cap only through the blend along their old edge.
let faces = named(&["side", "start", "F3:blend:side|start"]);
let names = qualify(faces, &[(0, 2), (1, 2)]);
assert_eq!(names.faces[0], "side");
assert_eq!(matches(&names, 0, "side#[start]"), Some(Match::Piece));
// A face the blend does not round an edge with is not one the side is told apart by.
assert_eq!(matches(&names, 0, "side#[top]"), Some(Match::Stem));
assert_eq!(matches(&names, 0, "side#[F3:blend:side|top]"), Some(Match::Stem), "a blend of another edge");
}
/// A blend face's own name is the edge it replaced, so the faces that told a piece of one apart
/// sit inside that name (`F3:blend:side#[start]|start`); the face whole again since is the blend
/// of the sides without their qualifiers (#4325).
#[test]
fn a_piece_of_a_blend_face_finds_it_once_it_is_one_face_again() {
let faces = named(&["F3:blend:side|start", "side", "start"]);
let names = qualify(faces, &[(0, 1), (0, 2)]);
assert_eq!(names.faces[0], "F3:blend:side|start");
assert_eq!(matches(&names, 0, "F3:blend:side#[start]|start"), Some(Match::Piece));
assert_eq!(matches(&names, 0, "F3:blend:side#[side]|start"), Some(Match::Piece));
// A face the blend no longer touches, inside its name: not its piece.
assert_eq!(matches(&names, 0, "F3:blend:side#[top]|start"), None);
// A qualifier on the side that is whole anyway is not a piece at all.
assert_eq!(matches(&names, 0, "F3:blend:side|start"), Some(Match::Exact));
// A pattern copy's blend: the qualifier carries the copy's instance, as the faces around the
// copy do, and the name compares within that copy only.
let copied = qualify(named(&["F3:blend:side|start@F9.1", "side@F9.1", "start@F9.1"]), &[(0, 1), (0, 2)]);
assert_eq!(matches(&copied, 0, "F3:blend:side#[start@F9.1]|start@F9.1"), Some(Match::Piece));
assert_eq!(matches(&copied, 0, "F3:blend:side#[start@F9.1]|start@F9.2"), None, "another copy");
}
/// Two pieces of one face that a blend tells apart from the same face both answer to the stored
/// name: one through the face itself, one through the blend that replaced its edge. The lookup
/// chooses neither (#4325).
#[test]
fn two_pieces_told_apart_by_one_blend_both_answer_to_a_stored_name() {
let doc = crate::Document {
features: serde_json::from_value(serde_json::json!([
{"id": 1, "name": "Box1", "type": "box", "corner": [0, 0, 0], "length": "40", "width": "30", "height": "10"},
{"id": 2, "name": "Round", "type": "fillet", "edges": [[20, 0, 10]], "radius": "2"},
// A slot through the front wall, top to bottom: the wall is two pieces, and each keeps
// the round along its own top edge.
{"id": 3, "name": "Slot", "type": "box", "corner": [15, -1, 0], "length": "10", "width": "12", "height": "12"},
{"id": 4, "name": "SlotCut", "type": "combine", "target": "Body1", "tools": ["Body2"], "operation": "cut"}
]))
.unwrap(),
..crate::Document::default()
};
let doc = crate::format::read(&doc.to_json()).unwrap();
let mut model = crate::Model::new();
model.evaluate(&doc);
let state = model.state();
let body = state.body("Body1").unwrap();
let names = crate::naming::names(body);
let stored = "F1:-y#[F1:+z]";
let answering: Vec<usize> =
(0..names.faces.len()).filter(|face| matches(&names, *face, stored).is_some_and(|level| level >= Match::Piece)).collect();
assert_eq!(answering.len(), 2, "{:?}", names.faces);
assert!(crate::name_lookup::locate_face_on_body(&state, Some("Body1"), stored, Vec3::new(5., 0., 4.)).is_none(), "two faces answer");
}
+9 -176
View File
@@ -5,14 +5,13 @@
use solidcraft_geom::prelude::*;
use std::cell::Cell;
use std::collections::BTreeSet;
use std::f64::consts::{PI, TAU};
use solidcore_record::Vec3;
use solidcraft_sketch::linalg;
use super::{
Assembly, Held, JointKind, MAX_LOOP_VALUES, MAX_LOOP_WORK, MAX_LOOPS, Solution, Tree, Values, apply_links, build, close_within, jacobian,
joint_values, largest, limit_bounds, link_chains, loop_groups, loop_scale, loose_gap, unknowns,
Assembly, Held, MAX_LOOP_VALUES, MAX_LOOP_WORK, MAX_LOOPS, Solution, Tree, Values, apply_links, build, close_within, jacobian, joint_values,
largest, limit_bounds, link_chains, loop_groups, loop_scale, loose_gap, unknowns,
};
use crate::{Document, ModelState, apply_point, apply_vector, mat_mul};
@@ -126,27 +125,8 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
return Err(format!("its chain and loops have more than {MAX_LOOP_VALUES} values"));
}
let scale = loop_scale(tree, &around, &vals);
let raw_bounds = limit_bounds(tree, &vars);
let mut bounds = raw_bounds.clone();
let start: Vec<f64> = vars.iter().map(|(id, i)| vals.get(id).and_then(|q| q.get(*i)).copied().unwrap_or(0.0)).collect();
// A ball joint moves by a turn from where it starts, not by its Euler angles (`BallTurn`).
let balls = ball_turns(tree, &vars, &start, &raw_bounds);
let mut x0 = start.clone();
for k in balls.iter().flat_map(|b| b.at..b.at + 3) {
if let (Some(x), Some(b)) = (x0.get_mut(k), bounds.get_mut(k)) {
(*x, *b) = (0.0, (f64::NEG_INFINITY, f64::INFINITY));
}
}
// The joints' values for the solve's `x`.
let values = |x: &[f64]| -> Vec<f64> {
let mut v = x.to_vec();
for b in &balls {
if let (Some(q), Some(slot)) = (b.values(x), v.get_mut(b.at..b.at + 3)) {
slot.copy_from_slice(&q);
}
}
v
};
let bounds = limit_bounds(tree, &vars);
let x0: Vec<f64> = vars.iter().map(|(id, i)| vals.get(id).and_then(|q| q.get(*i)).copied().unwrap_or(0.0)).collect();
// A distance steps by a share of the chain's size, of the way to the target or of the point's
// reach from its joints, whichever is longest (one slider on its own has no size, and a part
// turning about a joint far from its point moves that far).
@@ -167,9 +147,7 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
// a value a link sets can turn far more than the one that drives it, and a loop must stay
// closed on the way, as joint.drive steps its loops.
let mut paced: Vec<((u64, usize), f64)> = Vec::new();
// A ball joint is paced by its turn (`cap`) instead: near pitch 0 a small turn changes its yaw
// and roll a lot.
for j in around.iter().filter_map(|id| tree.joints.get(id)).filter(|j| !balls.iter().any(|b| b.id == j.id)) {
for j in around.iter().filter_map(|id| tree.joints.get(id)) {
for i in 0..j.kind.dofs().len() {
paced.push(((j.id, i), if j.kind.is_angle(i) { STEP_ANGLE.to_radians() } else { STEP_SHARE * span }));
}
@@ -179,11 +157,11 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
let spent = Cell::new(0usize);
let mut work = vals.clone();
let mut workspace = super::PlacementWorkspace::new(tree);
let mut f = |x: &[f64]| misses(&mut workspace, asm, r, scale, &vars, &closers, &values(x), &mut work, &spent);
let mut f = |x: &[f64]| misses(&mut workspace, asm, r, scale, &vars, &closers, x, &mut work, &spent);
let mut x = x0.clone();
let miss = |res: &[f64]| res.iter().take(mt).map(|v| v * v).sum::<f64>().sqrt();
let before = f(&x0).map_or(f64::INFINITY, |r| miss(&r));
let res = approach(&mut f, &|a, b| stride(asm, &vals, &vars, &paced, &values(a), &values(b)), mt, &mut x, &bounds, &cap, tol, loose_gap(scale))
let res = approach(&mut f, &|a, b| stride(asm, &vals, &vars, &paced, a, b), mt, &mut x, &bounds, &cap, tol, loose_gap(scale))
.ok_or("a closed loop on its chain is open and can't close (joint.list shows its conflict)")?;
let mut out = Reached::default();
let point_miss = res.iter().take(3).map(|v| v * v).sum::<f64>().sqrt();
@@ -206,17 +184,6 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
}
}
}
// A ball joint's value held at its limit (its turn isn't bounded; its values are).
for b in &balls {
for (i, (v, (lo, hi))) in b.values(&x).unwrap_or(b.start).iter().zip(b.bounds).enumerate() {
let at = |l: f64| l.is_finite() && (v - l).abs() <= 1e-9 * l.abs().max(1.0);
if at(hi) {
out.limits.push((b.id, i, true));
} else if at(lo) {
out.limits.push((b.id, i, false));
}
}
}
// A value a motion link sets, held at its own limit (the link clamps it there): the
// target's pull on it as if it were free.
if f(&x).is_some() {
@@ -253,8 +220,7 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
let mut alone = vals.clone();
let mut alone_workspace = super::PlacementWorkspace::new(tree);
let mut g = |x: &[f64]| misses(&mut alone_workspace, asm, r, scale, &drive, &[], x, &mut alone, &spent);
let (mut xo, bo, co) =
(start.get(..k).unwrap_or_default().to_vec(), raw_bounds.get(..k).unwrap_or_default(), cap.get(..k).unwrap_or_default());
let (mut xo, bo, co) = (x0.get(..k).unwrap_or_default().to_vec(), bounds.get(..k).unwrap_or_default(), cap.get(..k).unwrap_or_default());
// The loops left open, nothing to pace.
if let Some(ro) = approach(&mut g, &|_, _| 0.0, mt, &mut xo, bo, co, tol, loose_gap(scale))
&& miss(&ro) < miss(&res) - REACH_TOL.max(1e-9 * miss(&res))
@@ -266,7 +232,7 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
// The stored values that changed, when that got it closer (by more than the solver's noise:
// a held part doesn't creep).
let gained = before - miss(&res) > 1e-7;
for ((id, i), v) in vars.iter().zip(&values(&x)).filter(|_| gained) {
for ((id, i), v) in vars.iter().zip(&x).filter(|_| gained) {
let Some(j) = tree.joints.get(id) else { continue };
if j.values.get(*i) == Some(v) {
continue;
@@ -283,112 +249,6 @@ pub fn reach(doc: &Document, st: &ModelState, r: &Reach) -> Result<Reached, Stri
Ok(out)
}
/// A unit quaternion (w, x, y, z): a turn that composes without the lock of Euler angles.
#[derive(Clone, Copy, Debug)]
struct Quat([f64; 4]);
impl Quat {
fn mul(self, o: Quat) -> Quat {
let ([a1, b1, c1, d1], [a2, b2, c2, d2]) = (self.0, o.0);
Quat([
a1 * a2 - b1 * b2 - c1 * c2 - d1 * d2,
a1 * b2 + b1 * a2 + c1 * d2 - d1 * c2,
a1 * c2 - b1 * d2 + c1 * a2 + d1 * b2,
a1 * d2 + b1 * c2 - c1 * b2 + d1 * a2,
])
}
/// The turn by the rotation vector `w`: |w| radians about its direction.
fn exp([x, y, z]: [f64; 3]) -> Quat {
let t = (x * x + y * y + z * z).sqrt();
let (s, c) = (t / 2.0).sin_cos();
let k = if t < 1e-12 { 0.5 } else { s / t };
Quat([c, x * k, y * k, z * k])
}
/// A ball joint's turn for its (yaw, pitch, roll): about z, then y, then z (`motion`).
fn zyz([a, b, c]: [f64; 3]) -> Quat {
let (sa, ca) = (a / 2.0).sin_cos();
let (sb, cb) = (b / 2.0).sin_cos();
let (sc, cc) = (c / 2.0).sin_cos();
Quat([ca, 0.0, 0.0, sa]).mul(Quat([cb, 0.0, sb, 0.0])).mul(Quat([cc, 0.0, 0.0, sc]))
}
/// Its (yaw, pitch, roll): of the two sets (at pitch 0 or 180°, the many), the one nearest
/// `near`, each angle a whole number of turns from where it would wrap.
fn to_zyz(self, near: [f64; 3]) -> [f64; 3] {
let [a0, b0, c0] = near;
let n = self.0.iter().map(|v| v * v).sum::<f64>().sqrt().max(1e-300);
let [w, x, y, z] = self.0.map(|v| v / n);
let r22 = 1.0 - 2.0 * (x * x + y * y);
let (r02, r12) = (2.0 * (x * z + w * y), 2.0 * (y * z - w * x));
let (r20, r21) = (2.0 * (x * z - w * y), 2.0 * (y * z + w * x));
let (r00, r10) = (1.0 - 2.0 * (y * y + z * z), 2.0 * (x * y + w * z));
// Not acos(r22): that rounds a turn under about 1e-8 to none, and a finite difference
// there sees nothing tilt.
let sin_b = r02.hypot(r12);
let b = sin_b.atan2(r22);
if sin_b > 1e-12 {
let (a, c) = (r12.atan2(r02), r21.atan2(-r20));
let one = [wrap(a, a0), wrap(b, b0), wrap(c, c0)];
let two = [wrap(a + PI, a0), wrap(-b, b0), wrap(c + PI, c0)];
let off = |v: &[f64; 3]| (v[0] - a0).abs() + (v[1] - b0).abs() + (v[2] - c0).abs();
if off(&two) < off(&one) { two } else { one }
} else if r22 > 0.0 {
// Pitch 0: only yaw + roll is known; yaw stays.
[a0, wrap(0.0, b0), wrap(r10.atan2(r00) - a0, c0)]
} else {
// Pitch 180°: only roll − yaw is known; yaw stays.
[a0, wrap(PI, b0), wrap(a0 + r10.atan2(-r00), c0)]
}
}
}
/// `t` moved by whole turns to lie nearest `near`.
fn wrap(t: f64, near: f64) -> f64 {
t + TAU * ((near - t) / TAU).round()
}
/// A ball joint whose three values all move in a reach. It is solved over a small turn from where
/// it starts (a rotation vector in its own frame, radians) instead of its Euler angles, which lock
/// at pitch 0: there yaw and roll turn about the same axis, and nothing tilts it the other way
/// (#12873).
struct BallTurn {
id: u64,
/// Where its yaw is in the solve's values; pitch and roll follow.
at: usize,
from: Quat,
start: [f64; 3],
bounds: [(f64, f64); 3],
}
impl BallTurn {
/// Its (yaw, pitch, roll) for the turn in `x`, each held within its limits (pitch is the
/// angle between the joint's z axes, so its limits hold it in a cone, its yaw still free).
fn values(&self, x: &[f64]) -> Option<[f64; 3]> {
let w = x.get(self.at..self.at + 3)?;
let v = self.from.mul(Quat::exp([*w.first()?, *w.get(1)?, *w.get(2)?])).to_zyz(self.start);
let mut out = [0.0; 3];
for ((o, v), (lo, hi)) in out.iter_mut().zip(v).zip(self.bounds) {
*o = v.max(lo).min(hi);
}
Some(out)
}
}
/// The ball joints among `vars` with all three values there, in order.
fn ball_turns(tree: &Tree, vars: &[(u64, usize)], start: &[f64], bounds: &[(f64, f64)]) -> Vec<BallTurn> {
vars.windows(3)
.enumerate()
.filter_map(|(at, w)| {
let [(id, 0), (i1, 1), (i2, 2)] = w else { return None };
(id == i1 && id == i2 && tree.joints.get(id).is_some_and(|j| j.kind == JointKind::Ball)).then_some(())?;
let s = [*start.get(at)?, *start.get(at + 1)?, *start.get(at + 2)?];
Some(BallTurn { id: *id, at, from: Quat::zyz(s), start: s, bounds: [*bounds.get(at)?, *bounds.get(at + 1)?, *bounds.get(at + 2)?] })
})
.collect()
}
/// The target's misses with the values `vars` at `x`: the point's (mm), then the axis's (as mm
/// across the chain's `scale`), then the gaps of the loops `closers`, weighted.
fn misses(
@@ -608,33 +468,6 @@ mod tests {
use super::super::tests::{PLACEMENT_INSERTS, PLACEMENT_STEPS, chain, placement_tree};
use super::*;
/// A ball joint's quaternion is the turn `motion` places it by, and its angles come back
/// from it: the nearer of the two sets, and at pitch 0 the yaw it had.
#[test]
fn a_ball_turn_matches_the_joint_and_comes_back() {
let rot = |q: Quat, v: Vec3| {
let [w, x, y, z] = q.0;
let u = Vec3::new(x, y, z);
v + u.cross(v) * (2.0 * w) + u.cross(u.cross(v)) * 2.0
};
for zyz in [[0.3, 0.4, -1.2], [-2.0, -0.5, 0.7], [1.0, 3.0, 0.2], [0.5, 0.0, 0.25]] {
let (q, m) = (Quat::zyz(zyz), super::super::motion(JointKind::Ball, &zyz));
for v in [Vec3::X, Vec3::Y, Vec3::Z] {
assert!(rot(q, v).dist(apply_vector(&m, v)) < 1e-12, "{zyz:?} {v:?}");
}
let back = q.to_zyz(zyz);
assert!(back.iter().zip(zyz).all(|(a, b)| (a - b).abs() < 1e-9), "{zyz:?} -> {back:?}");
}
// Pitch negative, asked near it: the same turn as pitch positive, yaw and roll a half
// turn round, but given as it was.
let zyz = [0.2, -0.4, 0.1];
let back = Quat::zyz(zyz).to_zyz(zyz);
assert!(back.iter().zip(zyz).all(|(a, b)| (a - b).abs() < 1e-9), "{back:?}");
// A small turn off pitch 0 tilts it whichever way it points.
let tilted = Quat::zyz([0.0; 3]).mul(Quat::exp([0.05, 0.0, 0.0])).to_zyz([0.0; 3]);
assert!((tilted[1].abs() - 0.05).abs() < 1e-9, "{tilted:?}");
}
/// Exercise the IK callback itself: removing sharing at this call site must fail even if
/// the reusable placement helper still passes its own tests.
#[test]
-5
View File
@@ -87,7 +87,6 @@ pub mod sheet;
pub mod sketch_equation;
pub mod text_params;
pub mod thread_forms;
pub mod tolerance;
pub use assembly::{
BomType, IDENTITY, MAX_PLACEMENT_DEPTH, MAX_PLACEMENTS, Mat, Occurrence, WorldNames, apply_point, apply_vector, is_identity, is_placement,
@@ -168,11 +167,7 @@ mod feature_walk_tests;
#[cfg(test)]
mod named_projection_tests;
#[cfg(test)]
mod old_cap_anchor_tests;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod tolerance_tests;
mod anchor_frame;
pub use anchor_frame::state_in_face_anchor_frame;
-40
View File
@@ -96,46 +96,6 @@ pub fn locate_edge(b: &ModelBody, name: &str, near: Vec3) -> Result<EdgeHit, Str
}
}
/// Find a saved Sketch Project edge in its body. Older designs can name the edge between
/// numbered pieces of faces that now evaluate whole (`F4:side:l6#2|F4:side:l7#2`, now
/// `F4:side:l6|F4:side:l7`). Recover it only when the faces it separates are whole, the saved
/// point lies on it, and its name is exact. Other edge references still require the stored
/// name as picked.
pub(crate) fn locate_projected_edge(b: &ModelBody, name: &str, near: Vec3) -> Result<EdgeHit, String> {
locate_edge(b, name, near).or_else(|miss| recover_numbered_projected_edge(b, name, near).ok_or(miss))
}
fn recover_numbered_projected_edge(b: &ModelBody, name: &str, near: Vec3) -> Option<EdgeHit> {
if b.body.is_mesh() || !near.is_finite() {
return None;
}
// Each face of the name without its piece number (`F4:side:l6#2` is `F4:side:l6`).
let mut numbered = false;
let whole: Vec<&str> = name
.split('|')
.map(|part| match part.rsplit_once('#') {
Some((stem, number))
if !stem.is_empty()
&& strip_piece(stem) == stem
&& !number.is_empty()
&& !number.starts_with('0')
&& number.bytes().all(|digit| digit.is_ascii_digit()) =>
{
numbered = true;
stem
}
_ => part,
})
.collect();
if !numbered {
return None;
}
let hit = locate_edge(b, &whole.join("|"), near).ok().filter(|hit| hit.verified && hit.on_point)?;
// Each face it separates is whole: no other piece of it is left to be the one picked. The
// edge is verified by that name, so the faces it separates are the `whole` stems.
whole.iter().all(|face| faces_with_stem(b, face).len() == 1).then_some(hit)
}
/// Whether a face found at `level` is exactly the face a name named: the very name (or another
/// name of that very face: a face its feature made from several roles has each), or the named
/// piece told apart by the faces around it. A face the named one was merged into, or a face of
-71
View File
@@ -349,74 +349,3 @@ fn an_edge_named_by_a_piece_of_a_face_that_is_whole_again_is_found() {
let gone = whole.replace("F2:side:l4", "F2:side:l4#[F2:side:l2]");
assert!(crate::name_lookup::locate_edge(body, &gone, near).is_err(), "{gone}");
}
/// A ring turned from a rectangle on YZ about Z: each side of the rectangle makes one round face.
fn ring() -> Document {
let doc = Document {
features: serde_json::from_value(serde_json::json!([
{
"id": 1, "name": "Sketch1", "type": "sketch", "plane": {"name": "YZ", "type": "origin"},
"sketch": {
"points": [
{"fixed": true, "id": "origin", "pos": [0., 0.]},
{"fixed": false, "id": "p1", "pos": [10., 0.]},
{"fixed": false, "id": "p2", "pos": [20., 0.]},
{"fixed": false, "id": "p3", "pos": [20., 5.]},
{"fixed": false, "id": "p4", "pos": [10., 5.]}
],
"curves": [
{"a": 1, "b": 2, "construction": false, "id": "l1", "type": "line"},
{"a": 2, "b": 3, "construction": false, "id": "l2", "type": "line"},
{"a": 3, "b": 4, "construction": false, "id": "l3", "type": "line"},
{"a": 4, "b": 1, "construction": false, "id": "l4", "type": "line"}
],
"constraints": [],
"counters": {"l": 4, "p": 4}
}
},
{
"id": 2, "name": "Revolve1", "type": "revolve", "body_names": ["Ring"], "angle": "360 deg",
"axis": {"axis": "Z", "type": "world"}, "convention": "sketch_normal",
"operation": "new_body", "profiles": {"type": "all"}, "sketch": 1
}
]))
.unwrap(),
..Document::default()
};
crate::format::read(&doc.to_json()).unwrap()
}
#[test]
fn numbered_edge_projection_recovers_the_edge_between_whole_faces() {
// 0.30.1 split each round face of a revolve into numbered pieces; the edge between two of
// them is now the edge between the two whole faces, at the same place.
let doc = ring();
let mut model = crate::Model::new();
model.evaluate(&doc);
let state = model.state();
let at = Vec3::new(0., -20., 5.);
let source = LinkSource::Edge { body: "Ring".into(), at };
let resolved = crate::project::resolve(&doc, &BTreeMap::new(), &state, &Plane::XY, LinkKind::Project, &source).unwrap();
let mut sketch = Sketch::default();
let link = sketch.add_link(LinkKind::Project, source, &resolved.geom).unwrap();
let numbered = "F2:side:l2#2|F2:side:l3#2";
sketch.links[0].edge_name = Some(numbered.into());
let curves = sketch.link_curves(&link).len();
let saved = sketch.clone();
let warnings = crate::project::refresh_links(&doc, &BTreeMap::new(), &state, &Plane::XY, &mut sketch).unwrap();
assert!(warnings.is_empty(), "{warnings:?}");
assert!(!sketch.links[0].lost);
assert_eq!(sketch.links[0].edge_name.as_deref(), Some(numbered));
assert_eq!(sketch.link_curves(&link).len(), curves);
// Edges picked by fillets, holes and joints keep the name as picked.
let body = state.body("Ring").unwrap();
assert!(crate::naming::locate_edge(body, numbered, at).is_err(), "ordinary lookup stays strict");
// The saved point on another edge (the inner rim): not this edge, so it asks to reselect.
let mut elsewhere = saved;
elsewhere.links[0].source = LinkSource::Edge { body: "Ring".into(), at: Vec3::new(0., -10., 5.) };
let error = crate::project::refresh_links(&doc, &BTreeMap::new(), &state, &Plane::XY, &mut elsewhere).unwrap_err();
assert!(matches!(&error, crate::DocError::Reselect { reference, .. } if reference == numbered), "{error}");
}
+3 -29
View File
@@ -364,22 +364,6 @@ pub fn blend_seams(b: &ModelBody) -> Vec<BlendSeam> {
out
}
/// The two faces of the edge a blend face replaced (`F<feature>:blend:<face>|<face>`), `None` for
/// any other name (its copy's instance is not part of them). A fillet or chamfer face is named
/// after the edge it rounds, so its name is what tells the two faces it now separates instead of
/// that edge. The mark may sit inside another role (`F5:inner:F4:blend:A|B`).
pub(crate) fn blend_sides(name: &str) -> Option<(&str, &str)> {
const MARK: &str = ":blend:";
let (name, _) = split_instance(name);
let at = name.find(MARK)?;
// The role right before the mark is the feature that made the blend (`F4`).
let feature = name.get(..at)?.rsplit(':').next()?;
if !feature.strip_prefix('F').is_some_and(|k| !k.is_empty() && k.bytes().all(|b| b.is_ascii_digit())) {
return None;
}
edge_sides(name.get(at + MARK.len()..)?)
}
/// The two faces an edge name `<face A>|<face B>` joins. A blend face's own name holds the edge it
/// replaced (`F<feature>:blend:<face>|<face>`), so a side's name can hold `|` too: the split is the
/// one `|` outside every blend face's edge (`F1:+y` and `F3:blend:F1:+z|F2:side` for
@@ -875,19 +859,9 @@ fn role_name(f: &Feature, before: &ModelState, ps: &[Vec3], ns: &[Vec3], fi: usi
FeatureKind::Revolve { sketch, axis, .. } => {
let Some(ss) = before.sketch(sketch.0) else { return format!("F{fid}:face:{fi}") };
// The origin was written as its values when the feature was evaluated (`naming_feature`).
let Ok((o2, d2)) = crate::eval::revolve_axis(
&Default::default(),
ss,
axis,
before,
&|name| crate::eval::construction_axis_in(None, before, name, 0),
&|owner, curve| {
before
.sketch(owner)
.ok_or_else(|| crate::DocError::Unknown(format!("sketch {owner}")))
.and_then(|os| crate::eval::sketch_line_world(os, curve))
},
) else {
let Ok((o2, d2)) =
crate::eval::revolve_axis(&Default::default(), ss, axis, before, &|name| crate::eval::construction_axis_in(None, before, name, 0))
else {
return format!("F{fid}:face:{fi}");
};
let (o, d) = (ss.plane.to_world(o2), (ss.plane.to_world(o2 + d2) - ss.plane.to_world(o2)).normalized().unwrap_or(Vec3::Z));
File diff suppressed because one or more lines are too long
-70
View File
@@ -1,70 +0,0 @@
use crate::Document;
use solidcraft_geom::prelude::*;
/// Sketch1 (a stadium) and Extrude1, Sketch2 on Extrude1's bottom cap and Extrude2 joined from it,
/// then Sketch3 on the same cap, as 0.30.1 saved them (#13323): the attachments carry an
/// `extrude_cap` certificate, which the SMLib kernel's join no longer marks the cap with.
fn old_doc(edit: impl FnOnce(&mut serde_json::Value)) -> Document {
let mut fixture: serde_json::Value = serde_json::from_str(include_str!("old_cap_anchor_fixture.json")).unwrap();
edit(&mut fixture["features"]);
let doc = Document {
features: serde_json::from_value(fixture["features"].take()).unwrap(),
params: serde_json::from_value(fixture["params"].take()).unwrap(),
..Document::default()
};
crate::format::read(&doc.to_json()).unwrap()
}
fn evaluate(doc: &Document) -> crate::Model {
let mut model = crate::Model::new();
model.evaluate(doc);
model
}
fn old_design(edit: impl FnOnce(&mut serde_json::Value)) -> crate::Model {
evaluate(&old_doc(edit))
}
#[test]
fn the_name_does_not_rescue_a_cap_on_an_offset_body() {
// Moved 5 mm along the cap's own plane: the plane and the saved point still match the body as
// built, but the sketch would stay behind at the old place. It stays lost instead.
let mut doc = old_doc(|_| {});
let mut offset = crate::IDENTITY;
offset[3][0] = 5.;
doc.body_offsets.insert("Body1".into(), offset);
let model = evaluate(&doc);
assert!(model.result(5).unwrap().error.is_some(), "{:?}", model.result(5));
}
fn sketch3(features: &mut serde_json::Value) -> &mut serde_json::Value {
features.as_array_mut().unwrap().iter_mut().find(|f| f["name"] == "Sketch3").unwrap()
}
#[test]
fn a_sketch_on_a_cap_that_a_join_left_uncertified_is_found_by_its_name() {
let model = old_design(|_| {});
for id in [1, 2, 3, 4, 5] {
assert!(model.result(id).unwrap().error.is_none(), "feature {id}: {:?}", model.result(id).map(|r| (&r.name, &r.error)));
}
let state = model.state();
let sketch = &state.sketch(5).expect("Sketch3 should be built").plane;
// The plane the file saved: origin (0, 0, 0), x direction (-1, 0, 0), normal +Y.
assert!(sketch.origin.len() < 1e-9, "{sketch:?}");
assert!((sketch.x - solidcore_record::Vec3::new(-1.0, 0.0, 0.0)).len() < 1e-9, "{sketch:?}");
assert!((sketch.normal() - solidcore_record::Vec3::new(0.0, 1.0, 0.0)).len() < 1e-9, "{sketch:?}");
}
#[test]
fn the_name_does_not_rescue_a_cap_that_is_not_where_the_sketch_was() {
// The plane the sketch was attached in is 1 mm off the face the name finds now.
let model = old_design(|features| {
sketch3(features)["plane"]["plane"]["origin"] = serde_json::json!([0.0, 1.0, 0.0]);
});
assert!(model.result(5).unwrap().error.is_some(), "{:?}", model.result(5));
// A name that is no longer a face of the body is not guessed either.
let model = old_design(|features| {
sketch3(features)["plane"]["name"] = serde_json::json!("F2:end");
});
assert!(model.result(5).unwrap().error.is_some(), "{:?}", model.result(5));
}

Some files were not shown because too many files have changed in this diff Show More