Compare commits
116 Commits
06911d27aa
...
fix/submod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d28c54b54f | ||
| 0bc2cf3b6a | |||
|
|
0330396843 | ||
|
|
6690d0355a | ||
| 7fe046379b | |||
|
|
0bc03ea421 | ||
| 0c43957e9b | |||
|
|
2ce00a527a | ||
| 967e434607 | |||
|
|
264e82179d | ||
|
|
40fac46862 | ||
| ed71a0c8b9 | |||
| 0ea2622a73 | |||
|
|
9748384e7d | ||
|
|
bb14d7b0ef | ||
| 099d2a025a | |||
| 3e93f4a756 | |||
| 8b6205a340 | |||
| 6fe5cc1d4d | |||
|
|
29f4a7b110 | ||
|
|
e947822c7a | ||
| 92183ef697 | |||
| b721e67c8d | |||
|
|
90728414a9 | ||
| d87b79698f | |||
|
|
65f24b23eb | ||
|
|
deb425db44 | ||
|
|
e70348508e | ||
| 41669eea8b | |||
|
|
ea49736549 | ||
|
|
99f2a92df4 | ||
| 4510ace7b9 | |||
| a1105c9d80 | |||
| 06c698d425 | |||
| 252e2c3b3e | |||
| 68380357fb | |||
| 076a1e90b0 | |||
| ab2fde4755 | |||
| 5d8a253956 | |||
| 6c11d64c5f | |||
| 0ffa171c52 | |||
| acfb627d67 | |||
| 64edae4c04 | |||
| 0ea1b1fde5 | |||
| e667aceead | |||
| 34964066a0 | |||
| 33026b6ff9 | |||
|
|
9dd43a7cc3 | ||
| 98d1877472 | |||
| 587a95dd66 | |||
| 73f6641199 | |||
| 60ceb47e4f | |||
| a8df078eb3 | |||
| f4d91db094 | |||
| b083970a4d | |||
|
|
d7b532255b | ||
| 19a91cb221 | |||
|
|
2fa1672edf | ||
|
|
d497471ed3 | ||
| 7b1662a3d1 | |||
|
|
128d7e0710 | ||
| c9d38d92aa | |||
|
|
002619b213 | ||
| 6bb080773b | |||
|
|
1dbeff7758 | ||
| cbc09cd3c5 | |||
|
|
1762bd23d1 | ||
| 6caf7375c2 | |||
| 190834716b | |||
| 6e41aa67fe | |||
|
|
b60f017363 | ||
|
|
7bbe856ba4 | ||
| 3de92325a3 | |||
|
|
e10841a6c8 | ||
| cecdb2e68c | |||
| 01ed1cf7ee | |||
| 294da1dc03 | |||
| e6dd3c6896 | |||
| e3ce32ca8a | |||
| 2b1519d7ba | |||
| fae8289e89 | |||
| 645e1b4607 | |||
|
|
fd371573fd | ||
|
|
9a566cabf9 | ||
|
|
3804164158 | ||
|
|
79501bd5ca | ||
| 83672c8c05 | |||
|
|
d7f5393510 | ||
| f5412a58fc | |||
|
|
7fb3aa4c01 | ||
| a5a1914892 | |||
|
|
9da73fe6e7 | ||
| 4cb8a3a1ec | |||
|
|
fa92f5a4d9 | ||
|
|
4a54e9b7cd | ||
| 54b1baa393 | |||
|
|
8f02c0d6f2 | ||
| 40fef9be85 | |||
| 8a8443607b | |||
| f6d588a7fa | |||
|
|
bae7c22e60 | ||
|
|
99a53d0ab2 | ||
| 2e6f06065a | |||
|
|
b3a58a6d92 | ||
| 2c564bea8a | |||
|
|
e443538548 | ||
| be0f8128ec | |||
|
|
48f5cc9311 | ||
| cb4b3363ec | |||
| 4334c9a494 | |||
| abc53e6b93 | |||
|
|
332e14f1f7 | ||
|
|
06475d5291 | ||
|
|
172f5cddee | ||
| f06bb96fdb | |||
|
|
04835c3629 |
3
.gitignore
vendored
@@ -74,3 +74,6 @@ files_to_translate.txt
|
||||
|
||||
# mdBook build output
|
||||
docs/book/
|
||||
|
||||
# To regenerate themed icons: python3 icons/retheme.py
|
||||
# icons/themed/ is tracked (committed) so CI builds include them
|
||||
|
||||
2
.gitmodules
vendored
@@ -13,6 +13,8 @@
|
||||
[submodule "mods/ztools"]
|
||||
path = mods/ztools
|
||||
url = https://git.kindred-systems.com/forbes/ztools.git
|
||||
branch = main
|
||||
[submodule "mods/silo"]
|
||||
path = mods/silo
|
||||
url = https://git.kindred-systems.com/kindred/silo-mod.git
|
||||
branch = main
|
||||
|
||||
@@ -5,42 +5,116 @@
|
||||
```
|
||||
FreeCAD startup
|
||||
└─ src/Mod/Create/Init.py
|
||||
└─ setup_kindred_addons()
|
||||
├─ exec(mods/ztools/ztools/Init.py)
|
||||
└─ exec(mods/silo/freecad/Init.py)
|
||||
└─ addon_loader.load_addons(gui=False)
|
||||
├─ scan_addons("mods/") — find package.xml manifests
|
||||
├─ parse_manifest() — extract <kindred> extensions
|
||||
├─ validate_manifest() — check min/max_create_version
|
||||
├─ resolve_load_order() — topological sort by <dependency>
|
||||
└─ for each addon in order:
|
||||
├─ add addon dir to sys.path
|
||||
├─ exec(Init.py)
|
||||
└─ register in AddonRegistry (FreeCAD.KindredAddons)
|
||||
|
||||
└─ src/Mod/Create/InitGui.py
|
||||
├─ setup_kindred_workbenches()
|
||||
│ ├─ exec(mods/ztools/ztools/InitGui.py)
|
||||
│ │ └─ schedules deferred _register() (2000ms)
|
||||
│ │ ├─ imports ZTools commands
|
||||
│ │ ├─ installs _ZToolsManipulator (global)
|
||||
│ │ └─ injects commands into editing contexts
|
||||
│ └─ exec(mods/silo/freecad/InitGui.py)
|
||||
│ ├─ registers SiloWorkbench
|
||||
│ └─ schedules deferred Silo overlay registration (2500ms)
|
||||
├─ addon_loader.load_addons(gui=True)
|
||||
│ └─ for each addon in order:
|
||||
│ └─ exec(InitGui.py)
|
||||
│ ├─ sdk (priority 0): logs "SDK loaded"
|
||||
│ ├─ ztools (priority 50): schedules deferred _register() (2000ms)
|
||||
│ │ ├─ imports ZTools commands
|
||||
│ │ ├─ installs _ZToolsManipulator (global)
|
||||
│ │ └─ injects commands into editing contexts
|
||||
│ └─ silo (priority 60): registers SiloWorkbench
|
||||
│ └─ schedules deferred Silo overlay registration (2500ms)
|
||||
├─ EditingContextResolver singleton created (MainWindow constructor)
|
||||
│ ├─ registers built-in contexts (PartDesign, Sketcher, Assembly, Spreadsheet)
|
||||
│ ├─ connects to signalInEdit/signalResetEdit/signalActiveDocument/signalActivateView
|
||||
│ └─ BreadcrumbToolBar connected to contextChanged signal
|
||||
└─ Deferred setup (QTimer):
|
||||
├─ 500ms: _register_kc_format() → .kc file format
|
||||
├─ 1500ms: _register_silo_origin() → registers Silo FileOrigin
|
||||
├─ 2000ms: _setup_silo_auth_panel() → "Database Auth" dock
|
||||
├─ 2000ms: ZTools _register() → commands + manipulator
|
||||
├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay
|
||||
├─ 3000ms: _check_silo_first_start() → settings prompt
|
||||
├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock (SSE)
|
||||
├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock
|
||||
└─ 10000ms: _check_for_updates() → update checker (Gitea API)
|
||||
```
|
||||
|
||||
### Addon lifecycle
|
||||
|
||||
Each addon in `mods/` provides a `package.xml` manifest with a `<kindred>` extension block:
|
||||
|
||||
```xml
|
||||
<kindred>
|
||||
<min_create_version>0.1.0</min_create_version>
|
||||
<load_priority>50</load_priority>
|
||||
<pure_python>true</pure_python>
|
||||
<dependencies>
|
||||
<dependency>sdk</dependency>
|
||||
</dependencies>
|
||||
</kindred>
|
||||
```
|
||||
|
||||
The loader (`addon_loader.py`) processes addons in this order:
|
||||
|
||||
1. **Scan** — find all `mods/*/package.xml` files
|
||||
2. **Parse** — extract `<kindred>` metadata (version bounds, priority, dependencies)
|
||||
3. **Validate** — reject addons incompatible with the current Create version
|
||||
4. **Resolve** — topological sort by `<dependency>` declarations, breaking ties by `<load_priority>`
|
||||
5. **Load** — execute `Init.py` (console) then `InitGui.py` (GUI) for each addon
|
||||
6. **Register** — populate `FreeCAD.KindredAddons` registry with addon state
|
||||
|
||||
Current load order: **sdk** (0) → **ztools** (50) → **silo** (60)
|
||||
|
||||
## Key source layout
|
||||
|
||||
```
|
||||
src/Mod/Create/ Kindred bootstrap module (Python)
|
||||
├── Init.py Adds mods/ addon paths, loads Init.py files
|
||||
├── InitGui.py Loads workbenches, installs Silo manipulators
|
||||
src/Mod/Create/ Kindred Create module
|
||||
├── Init.py Console bootstrap — loads addons via manifest-driven loader
|
||||
├── InitGui.py GUI bootstrap — loads addons, Silo integration, update checker
|
||||
├── addon_loader.py Manifest-driven addon loader with dependency resolution
|
||||
├── kc_format.py .kc file format round-trip preservation
|
||||
├── version.py.in CMake template → version.py (build-time)
|
||||
└── update_checker.py Checks Gitea releases API for updates
|
||||
├── update_checker.py Checks Gitea releases API for updates
|
||||
├── CreateGlobal.h C++ export macros (CreateExport, CreateGuiExport)
|
||||
├── App/ C++ App library (CreateApp.so)
|
||||
│ ├── AppCreate.cpp Module entry point — PyMOD_INIT_FUNC(CreateApp)
|
||||
│ └── AppCreatePy.cpp Python module object (Py::ExtensionModule)
|
||||
└── Gui/ C++ Gui library (CreateGui.so)
|
||||
├── AppCreateGui.cpp Module entry point — PyMOD_INIT_FUNC(CreateGui)
|
||||
└── AppCreateGuiPy.cpp Python module object (Py::ExtensionModule)
|
||||
|
||||
mods/sdk/ [dir] Kindred addon SDK — stable API contract
|
||||
├── package.xml Manifest (priority 0, no dependencies)
|
||||
├── kindred_sdk/
|
||||
│ ├── __init__.py Public API re-exports
|
||||
│ ├── context.py Editing context wrappers (register_context, register_overlay, ...)
|
||||
│ ├── theme.py YAML-driven palette system (get_theme_tokens, load_palette, Palette)
|
||||
│ ├── origin.py FileOrigin registration (register_origin, unregister_origin)
|
||||
│ ├── dock.py Deferred dock panel helper (register_dock_panel)
|
||||
│ ├── compat.py Version detection (create_version, freecad_version)
|
||||
│ └── palettes/
|
||||
│ └── catppuccin-mocha.yaml 26 colors + 14 semantic roles
|
||||
└── Init.py / InitGui.py Minimal log messages
|
||||
|
||||
mods/ztools/ [submodule] command provider (not a workbench)
|
||||
├── package.xml Manifest (priority 50, depends on sdk)
|
||||
├── ztools/InitGui.py Deferred command registration + _ZToolsManipulator
|
||||
├── ztools/ztools/
|
||||
│ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
|
||||
│ ├── datums/core.py Datum creation via Part::AttachExtension
|
||||
│ └── resources/ Icons (SDK theme tokens), theme utilities
|
||||
└── CatppuccinMocha/ Theme preference pack (QSS)
|
||||
|
||||
mods/silo/ [submodule → silo-mod.git] FreeCAD workbench
|
||||
├── freecad/package.xml Manifest (priority 60, depends on sdk)
|
||||
├── silo-client/ [submodule → silo-client.git] shared API client
|
||||
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
|
||||
└── freecad/ FreeCAD workbench (Python)
|
||||
├── InitGui.py SiloWorkbench + overlay registration (via SDK)
|
||||
├── silo_commands.py Commands + FreeCADSiloSettings adapter
|
||||
└── silo_origin.py FileOrigin backend for Silo (via SDK)
|
||||
|
||||
src/Gui/EditingContext.h/.cpp EditingContextResolver singleton + context registry
|
||||
src/Gui/BreadcrumbToolBar.h/.cpp Color-coded breadcrumb toolbar (Catppuccin Mocha)
|
||||
@@ -49,22 +123,6 @@ src/Gui/CommandOrigin.cpp Origin_Commit/Pull/Push/Info/BOM commands
|
||||
src/Gui/OriginManager.h/.cpp Origin lifecycle management
|
||||
src/Gui/OriginSelectorWidget.h/.cpp UI for origin selection
|
||||
|
||||
mods/ztools/ [submodule] command provider (not a workbench)
|
||||
├── ztools/InitGui.py Deferred command registration + _ZToolsManipulator
|
||||
├── ztools/ztools/
|
||||
│ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
|
||||
│ ├── datums/core.py Datum creation via Part::AttachExtension
|
||||
│ └── resources/ Icons, theme utilities
|
||||
└── CatppuccinMocha/ Theme preference pack (QSS)
|
||||
|
||||
mods/silo/ [submodule -> silo-mod.git] FreeCAD workbench
|
||||
├── silo-client/ [submodule -> silo-client.git] shared API client
|
||||
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
|
||||
└── freecad/ FreeCAD workbench (Python)
|
||||
├── InitGui.py SiloWorkbench + Silo overlay context registration
|
||||
├── silo_commands.py Commands + FreeCADSiloSettings adapter
|
||||
└── silo_origin.py FileOrigin backend for Silo
|
||||
|
||||
src/Gui/Stylesheets/ QSS themes and SVG assets
|
||||
src/Gui/PreferencePacks/ KindredCreate preference pack (cfg + build-time QSS)
|
||||
```
|
||||
|
||||
@@ -116,4 +116,4 @@ Notable theme customizations beyond standard Catppuccin colors:
|
||||
|
||||
### Palette
|
||||
|
||||
All silo-* icons use the Catppuccin Mocha color scheme. See `kindred-icons/README.md` for palette specification and icon design standards.
|
||||
All silo-* icons use the Catppuccin Mocha color scheme. See `icons/kindred/README.md` for palette specification and icon design standards.
|
||||
|
||||
395
docs/DAG_CLIENT_INTEGRATION.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# DAG Client Integration Contract
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
This document describes what silo-mod and Headless Create runners need to implement to integrate with the Silo dependency DAG and worker system.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The DAG system has two client-side integration points:
|
||||
|
||||
1. **silo-mod workbench** (desktop) -- pushes DAG data to Silo on save or revision create.
|
||||
2. **silorunner + silo-mod** (headless) -- extracts DAGs, validates features, and exports geometry as compute jobs.
|
||||
|
||||
Both share the same Python codebase in the silo-mod repository. Desktop users call the code interactively; runners call it headlessly via `create --console`.
|
||||
|
||||
---
|
||||
|
||||
## 2. DAG Sync Payload
|
||||
|
||||
Clients push feature trees to Silo via:
|
||||
|
||||
```
|
||||
PUT /api/items/{partNumber}/dag
|
||||
Authorization: Bearer <user_token or runner_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### 2.1 Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Sketch001",
|
||||
"node_type": "sketch",
|
||||
"properties_hash": "a1b2c3d4e5f6...",
|
||||
"metadata": {
|
||||
"label": "Base Profile",
|
||||
"constraint_count": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"node_type": "pad",
|
||||
"properties_hash": "f6e5d4c3b2a1...",
|
||||
"metadata": {
|
||||
"label": "Main Extrusion",
|
||||
"length": 25.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source_key": "Sketch001",
|
||||
"target_key": "Pad001",
|
||||
"edge_type": "depends_on"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Field Reference
|
||||
|
||||
**Nodes:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `node_key` | string | yes | Unique within item+revision. Use Create's internal object name (e.g. `Sketch001`, `Pad003`). |
|
||||
| `node_type` | string | yes | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`. |
|
||||
| `properties_hash` | string | no | SHA-256 hex digest of the node's parametric inputs. Used for memoization. |
|
||||
| `validation_state` | string | no | One of: `clean`, `dirty`, `validating`, `failed`. Defaults to `clean`. |
|
||||
| `metadata` | object | no | Arbitrary key-value pairs for display or debugging. |
|
||||
|
||||
**Edges:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `source_key` | string | yes | The node that is depended upon. |
|
||||
| `target_key` | string | yes | The node that depends on the source. |
|
||||
| `edge_type` | string | no | One of: `depends_on` (default), `references`, `constrains`. |
|
||||
|
||||
**Direction convention:** Edges point from dependency to dependent. If Pad001 depends on Sketch001, the edge is `source_key: "Sketch001"`, `target_key: "Pad001"`.
|
||||
|
||||
### 2.3 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"synced": true,
|
||||
"node_count": 15,
|
||||
"edge_count": 14
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Computing properties_hash
|
||||
|
||||
The `properties_hash` enables memoization -- if a node's inputs haven't changed since the last validation, it can be skipped. Computing it:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
def compute_properties_hash(feature_obj):
|
||||
"""Hash the parametric inputs of a Create feature."""
|
||||
inputs = {}
|
||||
|
||||
if feature_obj.TypeId == "Sketcher::SketchObject":
|
||||
# Hash geometry + constraints
|
||||
inputs["geometry_count"] = feature_obj.GeometryCount
|
||||
inputs["constraint_count"] = feature_obj.ConstraintCount
|
||||
inputs["geometry"] = str(feature_obj.Shape.exportBrep())
|
||||
elif feature_obj.TypeId == "PartDesign::Pad":
|
||||
inputs["length"] = feature_obj.Length.Value
|
||||
inputs["type"] = str(feature_obj.Type)
|
||||
inputs["reversed"] = feature_obj.Reversed
|
||||
inputs["sketch"] = feature_obj.Profile[0].Name
|
||||
# ... other feature types
|
||||
|
||||
canonical = json.dumps(inputs, sort_keys=True)
|
||||
return hashlib.sha256(canonical.encode()).hexdigest()
|
||||
```
|
||||
|
||||
The exact inputs per feature type are determined by what parametric values affect the feature's geometry. Include anything that, if changed, would require recomputation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Feature Tree Walking
|
||||
|
||||
To extract the DAG from a Create document:
|
||||
|
||||
```python
|
||||
import FreeCAD
|
||||
|
||||
def extract_dag(doc):
|
||||
"""Walk a Create document and return nodes + edges."""
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
for obj in doc.Objects:
|
||||
# Skip non-feature objects
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
nodes.append({
|
||||
"node_key": obj.Name,
|
||||
"node_type": node_type,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
"metadata": {
|
||||
"label": obj.Label,
|
||||
"type_id": obj.TypeId,
|
||||
}
|
||||
})
|
||||
|
||||
# Walk dependencies via InList (objects this one depends on)
|
||||
for dep in obj.InList:
|
||||
if hasattr(dep, "TypeId") and classify_type(dep.TypeId):
|
||||
edges.append({
|
||||
"source_key": dep.Name,
|
||||
"target_key": obj.Name,
|
||||
"edge_type": "depends_on",
|
||||
})
|
||||
|
||||
return nodes, edges
|
||||
|
||||
|
||||
def classify_type(type_id):
|
||||
"""Map Create TypeIds to DAG node types."""
|
||||
mapping = {
|
||||
"Sketcher::SketchObject": "sketch",
|
||||
"PartDesign::Pad": "pad",
|
||||
"PartDesign::Pocket": "pocket",
|
||||
"PartDesign::Fillet": "fillet",
|
||||
"PartDesign::Chamfer": "chamfer",
|
||||
"PartDesign::Body": "body",
|
||||
"Part::Feature": "part",
|
||||
"Sketcher::SketchConstraint": "constraint",
|
||||
}
|
||||
return mapping.get(type_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. When to Push DAG Data
|
||||
|
||||
Push the DAG to Silo in these scenarios:
|
||||
|
||||
| Event | Trigger | Who |
|
||||
|-------|---------|-----|
|
||||
| User saves in silo-mod | On save callback | Desktop silo-mod workbench |
|
||||
| User creates a revision | After `POST /api/items/{pn}/revisions` succeeds | Desktop silo-mod workbench |
|
||||
| Runner extracts DAG | After `create-dag-extract` job completes | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
| Runner validates | After `create-validate` job, push updated validation states | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Runner Entry Points
|
||||
|
||||
silo-mod must provide these Python entry points for headless invocation:
|
||||
|
||||
### 6.1 silo.runner.dag_extract
|
||||
|
||||
Extracts the feature DAG from a Create file and writes it as JSON.
|
||||
|
||||
```python
|
||||
# silo/runner.py
|
||||
|
||||
def dag_extract(input_path, output_path):
|
||||
"""
|
||||
Extract feature DAG from a Create file.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc (Kindred Create) file.
|
||||
output_path: Path to write the JSON output.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"nodes": [...], // Same format as DAG sync payload
|
||||
"edges": [...]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
nodes, edges = extract_dag(doc)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"nodes": nodes, "edges": edges}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.2 silo.runner.validate
|
||||
|
||||
Rebuilds all features and reports pass/fail per node.
|
||||
|
||||
```python
|
||||
def validate(input_path, output_path):
|
||||
"""
|
||||
Validate a Create file by rebuilding all features.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"valid": true/false,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"state": "clean", // or "failed"
|
||||
"message": null, // error message if failed
|
||||
"properties_hash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
doc.recompute()
|
||||
|
||||
results = []
|
||||
all_valid = True
|
||||
for obj in doc.Objects:
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
state = "clean"
|
||||
message = None
|
||||
if hasattr(obj, "isValid") and not obj.isValid():
|
||||
state = "failed"
|
||||
message = f"Feature {obj.Label} failed to recompute"
|
||||
all_valid = False
|
||||
|
||||
results.append({
|
||||
"node_key": obj.Name,
|
||||
"state": state,
|
||||
"message": message,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
})
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"valid": all_valid, "nodes": results}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.3 silo.runner.export
|
||||
|
||||
Exports geometry to STEP, IGES, or other formats.
|
||||
|
||||
```python
|
||||
def export(input_path, output_path, format="step"):
|
||||
"""
|
||||
Export a Create file to an external format.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc file.
|
||||
output_path: Path to write the exported file.
|
||||
format: Export format ("step", "iges", "stl", "obj").
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
|
||||
import Part
|
||||
shapes = [obj.Shape for obj in doc.Objects if hasattr(obj, "Shape")]
|
||||
compound = Part.makeCompound(shapes)
|
||||
|
||||
format_map = {
|
||||
"step": "STEP",
|
||||
"iges": "IGES",
|
||||
"stl": "STL",
|
||||
"obj": "OBJ",
|
||||
}
|
||||
|
||||
Part.export([compound], output_path)
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Headless Invocation
|
||||
|
||||
The `silorunner` binary shells out to Create (with silo-mod installed):
|
||||
|
||||
```bash
|
||||
# DAG extraction
|
||||
create --console -e "from silo.runner import dag_extract; dag_extract('/tmp/job/part.kc', '/tmp/job/dag.json')"
|
||||
|
||||
# Validation
|
||||
create --console -e "from silo.runner import validate; validate('/tmp/job/part.kc', '/tmp/job/result.json')"
|
||||
|
||||
# Export
|
||||
create --console -e "from silo.runner import export; export('/tmp/job/part.kc', '/tmp/job/output.step', 'step')"
|
||||
```
|
||||
|
||||
**Prerequisites:** The runner host must have:
|
||||
- Headless Create installed (Kindred's fork of FreeCAD)
|
||||
- silo-mod installed as a Create addon (so `from silo.runner import ...` works)
|
||||
- No display server required -- `--console` mode is headless
|
||||
|
||||
---
|
||||
|
||||
## 8. Validation Result Handling
|
||||
|
||||
After a runner completes a `create-validate` job, it should:
|
||||
|
||||
1. Read the result JSON.
|
||||
2. Push updated validation states via `PUT /api/runner/jobs/{jobID}/dag`:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{"node_key": "Sketch001", "node_type": "sketch", "validation_state": "clean", "properties_hash": "abc..."},
|
||||
{"node_key": "Pad001", "node_type": "pad", "validation_state": "failed", "properties_hash": "def..."}
|
||||
],
|
||||
"edges": [
|
||||
{"source_key": "Sketch001", "target_key": "Pad001"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Complete the job via `POST /api/runner/jobs/{jobID}/complete` with the summary result.
|
||||
|
||||
---
|
||||
|
||||
## 9. SSE Events
|
||||
|
||||
Clients should listen for these events on `GET /api/events`:
|
||||
|
||||
| Event | Payload | When |
|
||||
|-------|---------|------|
|
||||
| `dag.updated` | `{item_id, part_number, revision_number, node_count, edge_count}` | After any DAG sync |
|
||||
| `dag.validated` | `{item_id, part_number, valid, failed_count}` | After validation completes |
|
||||
| `job.created` | `{job_id, definition_name, trigger, item_id}` | Job auto-triggered or manually created |
|
||||
| `job.claimed` | `{job_id, runner_id, runner}` | Runner claims a job |
|
||||
| `job.progress` | `{job_id, progress, message}` | Runner reports progress |
|
||||
| `job.completed` | `{job_id, runner_id}` | Job finishes successfully |
|
||||
| `job.failed` | `{job_id, runner_id, error}` | Job fails |
|
||||
| `job.cancelled` | `{job_id, cancelled_by}` | Job cancelled by user |
|
||||
|
||||
---
|
||||
|
||||
## 10. Cross-Item Edges
|
||||
|
||||
For assembly constraints that reference geometry in child parts (e.g. a mate constraint between two parts), use the `dag_cross_edges` table. These edges bridge the BOM DAG and the feature DAG.
|
||||
|
||||
Cross-item edges are **not** included in the standard `PUT /dag` sync. They will be managed through a dedicated endpoint in a future iteration once the assembly constraint model in Create/silo-mod is finalized.
|
||||
|
||||
For now, the DAG sync covers intra-item dependencies only. Assembly-level interference detection uses the BOM DAG (`relationships` table) combined with per-item feature DAGs.
|
||||
@@ -468,7 +468,7 @@ The `kc_version` field in `silo/manifest.json` tracks the schema version. When t
|
||||
| MIME type | `application/x-kindred-create` |
|
||||
| UTI (macOS) | `com.kindred-systems.create.document` |
|
||||
| Magic bytes | `PK` (ZIP header, offset 0) + `silo/manifest.json` entry present |
|
||||
| Icon | Kindred Create document icon (from `kindred-icons/` asset set) |
|
||||
| Icon | Kindred Create document icon (from `icons/kindred/` asset set) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
5. **No unit tests.** Zero test coverage for ztools and Silo FreeCAD commands. Silo Go backend also lacks tests.
|
||||
|
||||
6. **Assembly solver datum handling is minimal.** The `findPlacement()` fix in `src/Mod/Assembly/UtilsAssembly.py` extracts placement from `obj.Shape.Faces[0]` for `PartDesign::Plane` and from shape vertex for `PartDesign::Point`. Does not handle empty shapes or non-planar datum objects.
|
||||
6. **Assembly solver datum handling is minimal.** `UtilsAssembly.findPlacement()` handles standard shapes (faces, edges, vertices) and `App::Line` origin objects. It does not extract placement from `PartDesign::Plane` or `PartDesign::Point` datum objects — when no element is selected, it returns a default `App.Placement()`. This means assembly joints referencing datum planes/points may produce incorrect placement.
|
||||
|
||||
### Medium
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
9. **tangent_to_cylinder falls back to manual placement.** TangentPlane MapMode requires a vertex reference not collected by the current UI.
|
||||
|
||||
10. **`delete_bom_entry()` bypasses error normalization.** Uses raw `urllib.request` instead of `SiloClient._request()`.
|
||||
10. ~~**`delete_bom_entry()` bypasses error normalization.**~~ Resolved. `delete_bom_entry()` uses `self._request("DELETE", ...)` which routes through `SiloClient._request()` with proper error handling.
|
||||
|
||||
11. **Missing Silo icons.** Three commands reference icons that don't exist: `silo-tag.svg` (`Silo_TagProjects`), `silo-rollback.svg` (`Silo_Rollback`), `silo-status.svg` (`Silo_SetStatus`). The `_icon()` function returns an empty string, so these commands render without toolbar icons.
|
||||
11. ~~**Missing Silo icons.**~~ Resolved. All three icons now exist: `silo-tag.svg`, `silo-rollback.svg`, `silo-status.svg` in `mods/silo/freecad/resources/icons/`.
|
||||
|
||||
### Fixed (retain for reference)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
| CSRF protection | Implemented | `nosurf` library on web form routes |
|
||||
| File locking | Not implemented | Needed to prevent concurrent edits |
|
||||
| Odoo ERP integration | Stub only | Returns "not yet implemented" |
|
||||
| Part number date segments | Broken | `formatDate()` returns error |
|
||||
| Part number date segments | Unknown | `formatDate()` reference is stale — function not found in codebase |
|
||||
| Location/inventory APIs | Tables exist, no handlers | |
|
||||
| CSV import rollback | Not implemented | `bom_handlers.go` |
|
||||
| SSE event streaming | Implemented | Reconnect logic with exponential backoff |
|
||||
@@ -71,14 +71,20 @@
|
||||
|
||||
1. **Authentication hardening** -- Deploy FreeIPA and Keycloak infrastructure. End-to-end test LDAP and OIDC flows. Harden token rotation and session expiry.
|
||||
|
||||
2. **BOM-Assembly bridge** -- Auto-populate Silo BOM from Assembly component links on save.
|
||||
2. **BOM-Assembly bridge** -- Auto-populate Silo BOM from Assembly component links on save. See `docs/BOM_MERGE.md` for specification.
|
||||
|
||||
3. **File locking** -- Pessimistic locks on `Silo_Open` to prevent concurrent edits. Requires server-side lock table and client-side lock display.
|
||||
|
||||
4. **Build system** -- CMake install rules for `mods/` submodules so packages include ztools and Silo without manual steps.
|
||||
4. ~~**Build system**~~ Done. CMake install rules in `src/Mod/Create/CMakeLists.txt` handle all `mods/` submodules.
|
||||
|
||||
5. **Test coverage** -- Unit tests for ztools datum creation, Silo FreeCAD commands, and Go API endpoints.
|
||||
|
||||
6. **QSS consolidation** -- Eliminate the 3-copy QSS duplication via build-time copy or symlinks. The canonical source is `resources/preferences/KindredCreate/KindredCreate.qss`.
|
||||
6. ~~**QSS consolidation**~~ Done. Canonical QSS is `src/Gui/Stylesheets/KindredCreate.qss`; PreferencePacks copy generated at build time via `configure_file()`.
|
||||
|
||||
7. **Update notification UI** -- Display in-app notification when a new release is available (issue #30). The update checker backend is already implemented.
|
||||
7. **Update notification UI** -- Display in-app notification when a new release is available (issue #30). The update checker backend (`update_checker.py`) runs at startup; notification UI still needed.
|
||||
|
||||
8. **KC file format completion** -- Populate `silo_instance` and `revision_hash` in manifest.json. Implement write-back for history.json, approvals.json, dependencies.json. See `docs/KC_SPECIFICATION.md`.
|
||||
|
||||
9. **ztools SDK migration** -- Add `<kindred>` metadata to `mods/ztools/package.xml` (load priority, version bounds, SDK dependency). Migrate `InitGui.py` to use `kindred_sdk` APIs for context/overlay registration.
|
||||
|
||||
10. **DAG cross-item edges** -- Assembly constraints referencing geometry in child parts should populate `dag_cross_edges`. Deferred until assembly constraint model is finalized.
|
||||
|
||||
395
docs/MULTI_USER_CLIENT.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# DAG Client Integration Contract
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
This document describes what silo-mod and Headless Create runners need to implement to integrate with the Silo dependency DAG and worker system.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The DAG system has two client-side integration points:
|
||||
|
||||
1. **silo-mod workbench** (desktop) -- pushes DAG data to Silo on save or revision create.
|
||||
2. **silorunner + silo-mod** (headless) -- extracts DAGs, validates features, and exports geometry as compute jobs.
|
||||
|
||||
Both share the same Python codebase in the silo-mod repository. Desktop users call the code interactively; runners call it headlessly via `create --console`.
|
||||
|
||||
---
|
||||
|
||||
## 2. DAG Sync Payload
|
||||
|
||||
Clients push feature trees to Silo via:
|
||||
|
||||
```
|
||||
PUT /api/items/{partNumber}/dag
|
||||
Authorization: Bearer <user_token or runner_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### 2.1 Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Sketch001",
|
||||
"node_type": "sketch",
|
||||
"properties_hash": "a1b2c3d4e5f6...",
|
||||
"metadata": {
|
||||
"label": "Base Profile",
|
||||
"constraint_count": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"node_type": "pad",
|
||||
"properties_hash": "f6e5d4c3b2a1...",
|
||||
"metadata": {
|
||||
"label": "Main Extrusion",
|
||||
"length": 25.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source_key": "Sketch001",
|
||||
"target_key": "Pad001",
|
||||
"edge_type": "depends_on"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Field Reference
|
||||
|
||||
**Nodes:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `node_key` | string | yes | Unique within item+revision. Use Create's internal object name (e.g. `Sketch001`, `Pad003`). |
|
||||
| `node_type` | string | yes | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`. |
|
||||
| `properties_hash` | string | no | SHA-256 hex digest of the node's parametric inputs. Used for memoization. |
|
||||
| `validation_state` | string | no | One of: `clean`, `dirty`, `validating`, `failed`. Defaults to `clean`. |
|
||||
| `metadata` | object | no | Arbitrary key-value pairs for display or debugging. |
|
||||
|
||||
**Edges:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `source_key` | string | yes | The node that is depended upon. |
|
||||
| `target_key` | string | yes | The node that depends on the source. |
|
||||
| `edge_type` | string | no | One of: `depends_on` (default), `references`, `constrains`. |
|
||||
|
||||
**Direction convention:** Edges point from dependency to dependent. If Pad001 depends on Sketch001, the edge is `source_key: "Sketch001"`, `target_key: "Pad001"`.
|
||||
|
||||
### 2.3 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"synced": true,
|
||||
"node_count": 15,
|
||||
"edge_count": 14
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Computing properties_hash
|
||||
|
||||
The `properties_hash` enables memoization -- if a node's inputs haven't changed since the last validation, it can be skipped. Computing it:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
def compute_properties_hash(feature_obj):
|
||||
"""Hash the parametric inputs of a Create feature."""
|
||||
inputs = {}
|
||||
|
||||
if feature_obj.TypeId == "Sketcher::SketchObject":
|
||||
# Hash geometry + constraints
|
||||
inputs["geometry_count"] = feature_obj.GeometryCount
|
||||
inputs["constraint_count"] = feature_obj.ConstraintCount
|
||||
inputs["geometry"] = str(feature_obj.Shape.exportBrep())
|
||||
elif feature_obj.TypeId == "PartDesign::Pad":
|
||||
inputs["length"] = feature_obj.Length.Value
|
||||
inputs["type"] = str(feature_obj.Type)
|
||||
inputs["reversed"] = feature_obj.Reversed
|
||||
inputs["sketch"] = feature_obj.Profile[0].Name
|
||||
# ... other feature types
|
||||
|
||||
canonical = json.dumps(inputs, sort_keys=True)
|
||||
return hashlib.sha256(canonical.encode()).hexdigest()
|
||||
```
|
||||
|
||||
The exact inputs per feature type are determined by what parametric values affect the feature's geometry. Include anything that, if changed, would require recomputation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Feature Tree Walking
|
||||
|
||||
To extract the DAG from a Create document:
|
||||
|
||||
```python
|
||||
import FreeCAD
|
||||
|
||||
def extract_dag(doc):
|
||||
"""Walk a Create document and return nodes + edges."""
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
for obj in doc.Objects:
|
||||
# Skip non-feature objects
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
nodes.append({
|
||||
"node_key": obj.Name,
|
||||
"node_type": node_type,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
"metadata": {
|
||||
"label": obj.Label,
|
||||
"type_id": obj.TypeId,
|
||||
}
|
||||
})
|
||||
|
||||
# Walk dependencies via InList (objects this one depends on)
|
||||
for dep in obj.InList:
|
||||
if hasattr(dep, "TypeId") and classify_type(dep.TypeId):
|
||||
edges.append({
|
||||
"source_key": dep.Name,
|
||||
"target_key": obj.Name,
|
||||
"edge_type": "depends_on",
|
||||
})
|
||||
|
||||
return nodes, edges
|
||||
|
||||
|
||||
def classify_type(type_id):
|
||||
"""Map Create TypeIds to DAG node types."""
|
||||
mapping = {
|
||||
"Sketcher::SketchObject": "sketch",
|
||||
"PartDesign::Pad": "pad",
|
||||
"PartDesign::Pocket": "pocket",
|
||||
"PartDesign::Fillet": "fillet",
|
||||
"PartDesign::Chamfer": "chamfer",
|
||||
"PartDesign::Body": "body",
|
||||
"Part::Feature": "part",
|
||||
"Sketcher::SketchConstraint": "constraint",
|
||||
}
|
||||
return mapping.get(type_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. When to Push DAG Data
|
||||
|
||||
Push the DAG to Silo in these scenarios:
|
||||
|
||||
| Event | Trigger | Who |
|
||||
|-------|---------|-----|
|
||||
| User saves in silo-mod | On save callback | Desktop silo-mod workbench |
|
||||
| User creates a revision | After `POST /api/items/{pn}/revisions` succeeds | Desktop silo-mod workbench |
|
||||
| Runner extracts DAG | After `create-dag-extract` job completes | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
| Runner validates | After `create-validate` job, push updated validation states | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Runner Entry Points
|
||||
|
||||
silo-mod must provide these Python entry points for headless invocation:
|
||||
|
||||
### 6.1 silo.runner.dag_extract
|
||||
|
||||
Extracts the feature DAG from a Create file and writes it as JSON.
|
||||
|
||||
```python
|
||||
# silo/runner.py
|
||||
|
||||
def dag_extract(input_path, output_path):
|
||||
"""
|
||||
Extract feature DAG from a Create file.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc (Kindred Create) file.
|
||||
output_path: Path to write the JSON output.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"nodes": [...], // Same format as DAG sync payload
|
||||
"edges": [...]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
nodes, edges = extract_dag(doc)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"nodes": nodes, "edges": edges}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.2 silo.runner.validate
|
||||
|
||||
Rebuilds all features and reports pass/fail per node.
|
||||
|
||||
```python
|
||||
def validate(input_path, output_path):
|
||||
"""
|
||||
Validate a Create file by rebuilding all features.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"valid": true/false,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"state": "clean", // or "failed"
|
||||
"message": null, // error message if failed
|
||||
"properties_hash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
doc.recompute()
|
||||
|
||||
results = []
|
||||
all_valid = True
|
||||
for obj in doc.Objects:
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
state = "clean"
|
||||
message = None
|
||||
if hasattr(obj, "isValid") and not obj.isValid():
|
||||
state = "failed"
|
||||
message = f"Feature {obj.Label} failed to recompute"
|
||||
all_valid = False
|
||||
|
||||
results.append({
|
||||
"node_key": obj.Name,
|
||||
"state": state,
|
||||
"message": message,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
})
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"valid": all_valid, "nodes": results}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.3 silo.runner.export
|
||||
|
||||
Exports geometry to STEP, IGES, or other formats.
|
||||
|
||||
```python
|
||||
def export(input_path, output_path, format="step"):
|
||||
"""
|
||||
Export a Create file to an external format.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc file.
|
||||
output_path: Path to write the exported file.
|
||||
format: Export format ("step", "iges", "stl", "obj").
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
|
||||
import Part
|
||||
shapes = [obj.Shape for obj in doc.Objects if hasattr(obj, "Shape")]
|
||||
compound = Part.makeCompound(shapes)
|
||||
|
||||
format_map = {
|
||||
"step": "STEP",
|
||||
"iges": "IGES",
|
||||
"stl": "STL",
|
||||
"obj": "OBJ",
|
||||
}
|
||||
|
||||
Part.export([compound], output_path)
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Headless Invocation
|
||||
|
||||
The `silorunner` binary shells out to Create (with silo-mod installed):
|
||||
|
||||
```bash
|
||||
# DAG extraction
|
||||
create --console -e "from silo.runner import dag_extract; dag_extract('/tmp/job/part.kc', '/tmp/job/dag.json')"
|
||||
|
||||
# Validation
|
||||
create --console -e "from silo.runner import validate; validate('/tmp/job/part.kc', '/tmp/job/result.json')"
|
||||
|
||||
# Export
|
||||
create --console -e "from silo.runner import export; export('/tmp/job/part.kc', '/tmp/job/output.step', 'step')"
|
||||
```
|
||||
|
||||
**Prerequisites:** The runner host must have:
|
||||
- Headless Create installed (Kindred's fork of FreeCAD)
|
||||
- silo-mod installed as a Create addon (so `from silo.runner import ...` works)
|
||||
- No display server required -- `--console` mode is headless
|
||||
|
||||
---
|
||||
|
||||
## 8. Validation Result Handling
|
||||
|
||||
After a runner completes a `create-validate` job, it should:
|
||||
|
||||
1. Read the result JSON.
|
||||
2. Push updated validation states via `PUT /api/runner/jobs/{jobID}/dag`:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{"node_key": "Sketch001", "node_type": "sketch", "validation_state": "clean", "properties_hash": "abc..."},
|
||||
{"node_key": "Pad001", "node_type": "pad", "validation_state": "failed", "properties_hash": "def..."}
|
||||
],
|
||||
"edges": [
|
||||
{"source_key": "Sketch001", "target_key": "Pad001"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Complete the job via `POST /api/runner/jobs/{jobID}/complete` with the summary result.
|
||||
|
||||
---
|
||||
|
||||
## 9. SSE Events
|
||||
|
||||
Clients should listen for these events on `GET /api/events`:
|
||||
|
||||
| Event | Payload | When |
|
||||
|-------|---------|------|
|
||||
| `dag.updated` | `{item_id, part_number, revision_number, node_count, edge_count}` | After any DAG sync |
|
||||
| `dag.validated` | `{item_id, part_number, valid, failed_count}` | After validation completes |
|
||||
| `job.created` | `{job_id, definition_name, trigger, item_id}` | Job auto-triggered or manually created |
|
||||
| `job.claimed` | `{job_id, runner_id, runner}` | Runner claims a job |
|
||||
| `job.progress` | `{job_id, progress, message}` | Runner reports progress |
|
||||
| `job.completed` | `{job_id, runner_id}` | Job finishes successfully |
|
||||
| `job.failed` | `{job_id, runner_id, error}` | Job fails |
|
||||
| `job.cancelled` | `{job_id, cancelled_by}` | Job cancelled by user |
|
||||
|
||||
---
|
||||
|
||||
## 10. Cross-Item Edges
|
||||
|
||||
For assembly constraints that reference geometry in child parts (e.g. a mate constraint between two parts), use the `dag_cross_edges` table. These edges bridge the BOM DAG and the feature DAG.
|
||||
|
||||
Cross-item edges are **not** included in the standard `PUT /dag` sync. They will be managed through a dedicated endpoint in a future iteration once the assembly constraint model in Create/silo-mod is finalized.
|
||||
|
||||
For now, the DAG sync covers intra-item dependencies only. Assembly-level interference detection uses the BOM DAG (`relationships` table) combined with per-item feature DAGs.
|
||||
121
docs/UPSTREAM.md
@@ -36,7 +36,7 @@ These files/directories exist only in Kindred Create and can be copied directly
|
||||
|
||||
| Directory | Description |
|
||||
|-----------|-------------|
|
||||
| `kindred-icons/` | 1444 Catppuccin Mocha SVG icon overrides |
|
||||
| `icons/kindred/` | 1444 Catppuccin Mocha SVG icon overrides |
|
||||
| `mods/silo/` | Silo workbench submodule (`silo-mod`) |
|
||||
| `mods/ztools/` | ZTools workbench submodule |
|
||||
| `src/Mod/Create/` | Kindred Create workbench (InitGui.py, kc_format.py, update_checker.py, version.py.in) |
|
||||
@@ -74,46 +74,71 @@ These files/directories exist only in Kindred Create and can be copied directly
|
||||
|
||||
36 Kindred commits touch core FreeCAD C++ files. Of those, **38 files** also changed on `upstream/main`, creating potential conflicts. Listed in chronological order (oldest first) for cherry-pick sequence.
|
||||
|
||||
### Category legend
|
||||
|
||||
| Category | Meaning | Long-term plan |
|
||||
|----------|---------|----------------|
|
||||
| **1 — Extension** | Platform extension points for Python addons. Core differentiator. | KEEP — maintain and isolate |
|
||||
| **2 — Branding** | Branding and theming. Unavoidable in a fork. | KEEP — minimize surface area |
|
||||
| **3 — Bug fix** | Bug fixes and polish applicable to upstream FreeCAD. | UPSTREAM — contribute and eliminate |
|
||||
|
||||
### Commit sequence
|
||||
|
||||
| # | Hash | Summary | Conflict Risk | Files |
|
||||
|---|------|---------|---------------|-------|
|
||||
| 1 | `316d4f4b524` | Initial branding (CMakeLists, splash, about, theme, icons, QRC) | **HIGH** — CMakeLists.txt, DlgAbout.cpp, SplashScreen.cpp, resource.qrc all changed upstream | 14 files |
|
||||
| 2 | `8c6837cc152` | Theme padding/clipping fixes | LOW — KindredCreate.qss is new file | 1 file |
|
||||
| 3 | `bb3f3ac6d6c` | Dock task panel right, remove non-Kindred themes | **MEDIUM** — MainWindow.cpp, PreferencePacks CMakeLists changed upstream | 8 files |
|
||||
| 4 | `e85162947b7` | Startup theme selector fix | **MEDIUM** — StartupProcess.cpp changed upstream | 4 files |
|
||||
| 5 | `eb80c07f57a` | Theme QSS refinements | LOW — Kindred-only files | 4 files |
|
||||
| 6 | `8639b6fd8ab` | Resolve unknown command/style token errors | **MEDIUM** — StartupProcess.cpp | 5 files |
|
||||
| 7 | `fea1280fa90` | Theme alternate-background-color | LOW | 2 files |
|
||||
| 8 | `b3fedfb19fb` | Theme tree item padding | LOW | 2 files |
|
||||
| 9 | `0d4545b7d67` | Tree branch line SVGs | LOW — new files | 8 files |
|
||||
| 10 | `434ae797a43` | Theme selector cleanup | **MEDIUM** — StartupProcess.cpp | 4 files |
|
||||
| 11 | `224feda4ad6` | Catppuccin icon override infrastructure | **MEDIUM** — BitmapFactory.cpp, CMakeLists.txt | 2 files |
|
||||
| 12 | `7535a48ec4c` | Origin abstraction layer | **HIGH** — Application.cpp, ApplicationPy.cpp/.h, CMakeLists.txt | 6 files (4 new) |
|
||||
| 13 | `38358e431d2` | LocalFileOrigin and Std_* delegation | **HIGH** — CommandDoc.cpp, FileOrigin.cpp/.h | 3 files |
|
||||
| 14 | `79c85ed2e5d` | FileOriginPython interactive methods | LOW — Kindred-only files | 3 files |
|
||||
| 15 | `deeb6376f71` | OriginSelectorWidget | **HIGH** — Action.cpp/.h, CommandStd.cpp, Workbench.cpp, CMakeLists.txt | 8 files |
|
||||
| 16 | `679aaec6d49` | Origin commands (Commit/Pull/Push) | **MEDIUM** — Application.cpp, Command.h, Workbench.cpp | 5 files |
|
||||
| 17 | `db85277f262` | OriginManagerDialog | LOW — new files + OriginSelectorWidget.cpp | 3 files |
|
||||
| 18 | `015df38328c` | Document-origin tracking in window title | **MEDIUM** — MDIView.cpp | 3 files |
|
||||
| 19 | `a6e84552da5` | Cross-origin detection in SaveAs | **MEDIUM** — CommandDoc.cpp | 1 file |
|
||||
| 20 | `84b69b935b2` | Build fix: remove SelectModule.h include | LOW | 1 file |
|
||||
| 21 | `2f594dac0a5` | Use Python API for viewDefaultOrientation | **MEDIUM** — CommandDoc.cpp | 1 file |
|
||||
| 22 | `724440dcb75` | Build fixes for OriginSelectorWidget/Manager | LOW — Kindred files | 2 files |
|
||||
| 23 | `c858706d480` | Add silo icons to QRC | LOW — resource.qrc (additive) | 6 files |
|
||||
| 24 | `d95c850b7b1` | Widen origin selector widget | LOW | 1 file |
|
||||
| 25 | `10b5c9d584f` | Wire OriginManagerDialog to Silo_Settings | LOW | 1 file |
|
||||
| 26 | `cc5ba638d1f` | UI polish — Wayland scaling, menu icon size | **HIGH** — DlgSettingsGeneral.cpp/.h/.ui changed upstream | 6 files |
|
||||
| 27 | `4bf74cf3391` | Build fix for DlgSettingsGeneral | **MEDIUM** — DlgSettingsGeneral.h, StartupProcess.cpp | 2 files |
|
||||
| 28 | `6773ca0dfd8` | Eliminate QSS/CFG duplication | LOW — Kindred files | 3 files |
|
||||
| 29 | `977fa3c9347` | QGroupBox indicator, hyperlink color | LOW — KindredCreate.qss | 1 file |
|
||||
| 30 | `8b2ce4b73a4` | Native Qt start panel + kindred:// URL | **MEDIUM** — MainWindow.cpp | 1 file |
|
||||
| 31 | `bf637af4e45` | Window flickering and icon clipping fix | **MEDIUM** — MainWindow.cpp/.h | 3 files |
|
||||
| 32 | `70118201b02` | MDI pre-document tab for Silo new item | **HIGH** — ApplicationPy, BreadcrumbToolBar, EditingContext, MainWindow, Workbench | 11 files |
|
||||
| 33 | `1f49e3fa6da` | Build fix: ToolBarItem incomplete type, reportException | **LOW** — likely already fixed upstream | 2 files |
|
||||
| 34 | `f71decca089` | Splash screen: skip runtime draw, mantle bg | **MEDIUM** — SplashScreen.cpp | 3 files |
|
||||
| 35 | `2b0c6774c07` | Dev build defaults, skip version migration | **MEDIUM** — CMakeLists.txt, DlgVersionMigrator.cpp | 2 files |
|
||||
| 36 | `ab71902a4c2` | Forward visibility arg in appendToolbar() | LOW — FreeCADGuiInit.py | 1 file |
|
||||
| # | Hash | Summary | Category | Conflict Risk | Files |
|
||||
|---|------|---------|----------|---------------|-------|
|
||||
| 1 | `316d4f4b524` | Initial branding (CMakeLists, splash, about, theme, icons, QRC) | 2 — Branding | **HIGH** — CMakeLists.txt, DlgAbout.cpp, SplashScreen.cpp, resource.qrc all changed upstream | 14 files |
|
||||
| 2 | `8c6837cc152` | Theme padding/clipping fixes | 2 — Branding | LOW — KindredCreate.qss is new file | 1 file |
|
||||
| 3 | `bb3f3ac6d6c` | Dock task panel right, remove non-Kindred themes | 2 — Branding | **MEDIUM** — MainWindow.cpp, PreferencePacks CMakeLists changed upstream | 8 files |
|
||||
| 4 | `e85162947b7` | Startup theme selector fix | 2 — Branding | **MEDIUM** — StartupProcess.cpp changed upstream | 4 files |
|
||||
| 5 | `eb80c07f57a` | Theme QSS refinements | 2 — Branding | LOW — Kindred-only files | 4 files |
|
||||
| 6 | `8639b6fd8ab` | Resolve unknown command/style token errors | 2 — Branding | **MEDIUM** — StartupProcess.cpp | 5 files |
|
||||
| 7 | `fea1280fa90` | Theme alternate-background-color | 2 — Branding | LOW | 2 files |
|
||||
| 8 | `b3fedfb19fb` | Theme tree item padding | 2 — Branding | LOW | 2 files |
|
||||
| 9 | `0d4545b7d67` | Tree branch line SVGs | 2 — Branding | LOW — new files | 8 files |
|
||||
| 10 | `434ae797a43` | Theme selector cleanup | 2 — Branding | **MEDIUM** — StartupProcess.cpp | 4 files |
|
||||
| 11 | `224feda4ad6` | Catppuccin icon override infrastructure | 2 — Branding | **MEDIUM** — BitmapFactory.cpp, CMakeLists.txt | 2 files |
|
||||
| 12 | `7535a48ec4c` | Origin abstraction layer | 1 — Extension | **HIGH** — Application.cpp, ApplicationPy.cpp/.h, CMakeLists.txt | 6 files (4 new) |
|
||||
| 13 | `38358e431d2` | LocalFileOrigin and Std_* delegation | 1 — Extension | **HIGH** — CommandDoc.cpp, FileOrigin.cpp/.h | 3 files |
|
||||
| 14 | `79c85ed2e5d` | FileOriginPython interactive methods | 1 — Extension | LOW — Kindred-only files | 3 files |
|
||||
| 15 | `deeb6376f71` | OriginSelectorWidget | 1 — Extension | **HIGH** — Action.cpp/.h, CommandStd.cpp, Workbench.cpp, CMakeLists.txt | 8 files |
|
||||
| 16 | `679aaec6d49` | Origin commands (Commit/Pull/Push) | 1 — Extension | **MEDIUM** — Application.cpp, Command.h, Workbench.cpp | 5 files |
|
||||
| 17 | `db85277f262` | OriginManagerDialog | 1 — Extension | LOW — new files + OriginSelectorWidget.cpp | 3 files |
|
||||
| 18 | `015df38328c` | Document-origin tracking in window title | 1 — Extension | **MEDIUM** — MDIView.cpp | 3 files |
|
||||
| 19 | `a6e84552da5` | Cross-origin detection in SaveAs | 1 — Extension | **MEDIUM** — CommandDoc.cpp | 1 file |
|
||||
| 20 | `84b69b935b2` | Build fix: remove SelectModule.h include | 1 — Extension | LOW | 1 file |
|
||||
| 21 | `2f594dac0a5` | Use Python API for viewDefaultOrientation | 1 — Extension | **MEDIUM** — CommandDoc.cpp | 1 file |
|
||||
| 22 | `724440dcb75` | Build fixes for OriginSelectorWidget/Manager | 1 — Extension | LOW — Kindred files | 2 files |
|
||||
| 23 | `c858706d480` | Add silo icons to QRC | 2 — Branding | LOW — resource.qrc (additive) | 6 files |
|
||||
| 24 | `d95c850b7b1` | Widen origin selector widget | 1 — Extension | LOW | 1 file |
|
||||
| 25 | `10b5c9d584f` | Wire OriginManagerDialog to Silo_Settings | 1 — Extension | LOW | 1 file |
|
||||
| 26 | `cc5ba638d1f` | UI polish — Wayland scaling, menu icon size | 3 — Bug fix | **HIGH** — DlgSettingsGeneral.cpp/.h/.ui changed upstream | 6 files |
|
||||
| 27 | `4bf74cf3391` | Build fix for DlgSettingsGeneral | 3 — Bug fix | **MEDIUM** — DlgSettingsGeneral.h, StartupProcess.cpp | 2 files |
|
||||
| 28 | `6773ca0dfd8` | Eliminate QSS/CFG duplication | 2 — Branding | LOW — Kindred files | 3 files |
|
||||
| 29 | `977fa3c9347` | QGroupBox indicator, hyperlink color | 2 — Branding | LOW — KindredCreate.qss | 1 file |
|
||||
| 30 | `8b2ce4b73a4` | Native Qt start panel + kindred:// URL | 1 — Extension | **MEDIUM** — MainWindow.cpp | 1 file |
|
||||
| 31 | `bf637af4e45` | Window flickering and icon clipping fix | 3 — Bug fix | **MEDIUM** — MainWindow.cpp/.h | 3 files |
|
||||
| 32 | `70118201b02` | MDI pre-document tab for Silo new item | 1 — Extension | **HIGH** — ApplicationPy, BreadcrumbToolBar, EditingContext, MainWindow, Workbench | 11 files |
|
||||
| 33 | `1f49e3fa6da` | Build fix: ToolBarItem incomplete type, reportException | 3 — Bug fix | **LOW** — Kindred-specific build fix | 2 files |
|
||||
| 34 | `f71decca089` | Splash screen: skip runtime draw, mantle bg | 2 — Branding | **MEDIUM** — SplashScreen.cpp | 3 files |
|
||||
| 35 | `2b0c6774c07` | Dev build defaults, skip version migration | 2 — Branding | **MEDIUM** — CMakeLists.txt, DlgVersionMigrator.cpp | 2 files |
|
||||
| 36 | `ab71902a4c2` | Forward visibility arg in appendToolbar() | 1 — Extension | LOW — FreeCADGuiInit.py | 1 file |
|
||||
|
||||
### Category summary
|
||||
|
||||
| Category | Count | Commits |
|
||||
|----------|-------|---------|
|
||||
| 1 — Extension | 16 | #12–22, #24–25, #30, #32, #36 |
|
||||
| 2 — Branding | 16 | #1–11, #23, #28–29, #34–35 |
|
||||
| 3 — Bug fix | 4 | #26–27, #31, #33 |
|
||||
|
||||
### Category 3 — Upstream status (verified Feb 2026)
|
||||
|
||||
| # | Summary | Upstream Fixed? | FreeCAD Issues | Notes |
|
||||
|---|---------|-----------------|----------------|-------|
|
||||
| 26 | Wayland scaling, menu icon size pref | PARTIAL | [#25448](https://github.com/FreeCAD/FreeCAD/issues/25448), [#23830](https://github.com/FreeCAD/FreeCAD/issues/23830), [#23396](https://github.com/FreeCAD/FreeCAD/issues/23396) | Upstream has some HiDPI C++ fixes but Wayland fractional scaling still open. Menu icon size pref is a Kindred-added feature, not yet contributed. |
|
||||
| 27 | Build fix for DlgSettingsGeneral | NO | — | Companion to #26. `setMenuIconSize()` in StartupProcess is Kindred-added. |
|
||||
| 31 | Window flickering and icon clipping | NO | [#12917](https://github.com/FreeCAD/FreeCAD/issues/12917), [#18481](https://github.com/FreeCAD/FreeCAD/issues/18481) | Upstream still uses `setStyleSheet()` on statusBar causing repaint cascade. Good upstream PR candidate — replace with `setPalette()`. |
|
||||
| 33 | ToolBarItem incomplete type, reportException | N/A | — | Kindred-internal build fix. The `ToolBarItem` forward-decl issue only manifests with Kindred modifications to Workbench.h. The `reportException` typo is in Kindred-only editing context code. |
|
||||
|
||||
### HIGH conflict files (need manual attention)
|
||||
|
||||
@@ -137,14 +162,14 @@ These files are modified by both Kindred and upstream. They will almost certainl
|
||||
|
||||
## Phase 3: Module-Level Changes
|
||||
|
||||
### Assembly fixes (check if still needed)
|
||||
### Assembly fixes (verified Feb 2026)
|
||||
|
||||
| Hash | Summary | Status |
|
||||
|------|---------|--------|
|
||||
| `316d4f4b524` | Joint flip overconstrain fix | May be fixed upstream — verify |
|
||||
| `9dc50cef727` | SIGSEGV during document restore | May be fixed upstream — verify |
|
||||
| `ddefb236521` | Solver ignoring datum plane refs | May be fixed upstream — verify |
|
||||
| `b7374d7b1fc` | findPlacement() datum/origin handling | May be fixed upstream — verify |
|
||||
| Hash | Summary | Upstream Status | Action |
|
||||
|------|---------|-----------------|--------|
|
||||
| `316d4f4b524` | Joint flip overconstrain fix (91° rotation guard) | **NOT fixed** — upstream has basic grounded-object validation only. [FreeCAD#20377](https://github.com/FreeCAD/FreeCAD/issues/20377) open. | KEEP — re-apply |
|
||||
| `9dc50cef727` | SIGSEGV during document restore (`isRestoring()` guard) | **NOT fixed** — upstream `onChanged()` has no restore guard. [FreeCAD#18225](https://github.com/FreeCAD/FreeCAD/issues/18225) closed via different path. | KEEP — re-apply |
|
||||
| `ddefb236521` | Solver ignoring datum plane refs (`PartDesign::Plane`/`Point`) | **NOT fixed** — upstream `findPlacement()` lacks these types. | KEEP — re-apply, upstream candidate |
|
||||
| `b7374d7b1fc` | findPlacement() datum/origin handling (`App::Plane`/`Point`) | **PARTIAL** — `App::Line` fixed upstream via [PR#20026](https://github.com/FreeCAD/FreeCAD/pull/20026). `App::Plane`/`App::Point` still missing. | KEEP — re-apply the `Plane`/`Point` parts only |
|
||||
|
||||
Files touched: `src/Mod/Assembly/App/AssemblyObject.cpp`, `src/Mod/Assembly/UtilsAssembly.py`, `src/Mod/Assembly/InitGui.py`
|
||||
|
||||
@@ -179,7 +204,7 @@ Files touched: `src/Mod/Assembly/App/AssemblyObject.cpp`, `src/Mod/Assembly/Util
|
||||
1. **Build**: Full CMake configure + build succeeds
|
||||
2. **Launch**: Application starts without errors, splash and about dialogs show Kindred branding
|
||||
3. **Theme**: KindredCreate theme loads correctly, QSS applies
|
||||
4. **Icons**: kindred-icons override system works (BitmapFactory loads from kindred-icons/)
|
||||
4. **Icons**: icon override system works (BitmapFactory loads from icons/kindred/)
|
||||
5. **Origin system**: FileOrigin, OriginManager, OriginSelectorWidget functional
|
||||
6. **Silo integration**: Auth panel, activity panel, save/commit/pull all work
|
||||
7. **File format**: `.kc` files open/save with silo/ directory preserved
|
||||
@@ -199,7 +224,7 @@ git fetch upstream
|
||||
git checkout -b kindred-on-upstream-1.2 upstream/main
|
||||
|
||||
# 3. Copy Kindred-only directories
|
||||
git checkout origin/main -- kindred-icons/ mods/ src/Mod/Create/ package/ docs/ \
|
||||
git checkout origin/main -- icons/ mods/ src/Mod/Create/ package/ docs/ \
|
||||
.gitea/ resources/kindred* banner-logo-light.png CONTRIBUTING.md .gitmodules
|
||||
|
||||
# 4. Copy new Kindred source files (no conflicts)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
- [Repository Structure](./development/repo-structure.md)
|
||||
- [Build System](./development/build-system.md)
|
||||
- [Gui Module Build](./development/gui-build-integration.md)
|
||||
- [Package.xml Schema Extensions](./development/package-xml-schema.md)
|
||||
|
||||
# Silo Server
|
||||
|
||||
@@ -50,6 +51,8 @@
|
||||
# Reference
|
||||
|
||||
- [Configuration](./reference/configuration.md)
|
||||
- [Create Module Bootstrap](./reference/create-module-bootstrap.md)
|
||||
- [Datum Creator](./reference/datum-creator.md)
|
||||
- [Glossary](./reference/glossary.md)
|
||||
|
||||
# C++ API Reference
|
||||
|
||||
109
docs/src/development/package-xml-schema.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Package.xml Schema Extensions
|
||||
|
||||
Kindred Create extends FreeCAD's standard `package.xml` addon manifest with a `<kindred>` element. This element provides metadata for the manifest-driven addon loader: version compatibility, load ordering, dependency declarations, and editing context registration.
|
||||
|
||||
The `<kindred>` element is ignored by FreeCAD's AddonManager and stock module loader. Addons with this element remain compatible with upstream FreeCAD.
|
||||
|
||||
## Field reference
|
||||
|
||||
| Field | Parsed by loader | Required | Default | Description |
|
||||
|---|---|---|---|---|
|
||||
| `min_create_version` | Yes | No | *(none)* | Minimum Kindred Create version. Addon is skipped if the running version is lower. |
|
||||
| `max_create_version` | Yes | No | *(none)* | Maximum Kindred Create version. Addon is skipped if the running version is higher. |
|
||||
| `load_priority` | Yes | No | `100` | Integer. Lower values load first. Used as a secondary sort after dependency resolution. |
|
||||
| `dependencies` | Yes | No | *(none)* | List of addon names (by `<name>` in their `package.xml`) that must load before this one. |
|
||||
| `sdk_version` | No | No | *(none)* | Required kindred-addon-sdk version. Reserved for future use when the SDK is available. |
|
||||
| `pure_python` | No | No | `true` | If `false`, the addon requires compiled C++ components. Informational. |
|
||||
| `contexts` | No | No | *(none)* | Editing contexts this addon registers or injects into. Informational. |
|
||||
|
||||
Fields marked "Parsed by loader" are read by `addon_loader.py` and affect load behavior. Other fields are informational metadata for tooling and documentation.
|
||||
|
||||
## Schema
|
||||
|
||||
```xml
|
||||
<kindred>
|
||||
<min_create_version>0.1.0</min_create_version>
|
||||
<max_create_version>1.0.0</max_create_version>
|
||||
<sdk_version>0.1.0</sdk_version>
|
||||
<load_priority>100</load_priority>
|
||||
<pure_python>true</pure_python>
|
||||
<dependencies>
|
||||
<dependency>sdk</dependency>
|
||||
<dependency>other-addon</dependency>
|
||||
</dependencies>
|
||||
<contexts>
|
||||
<context id="partdesign.body" action="inject"/>
|
||||
<context id="sketcher.edit" action="register"/>
|
||||
<context id="*" action="overlay"/>
|
||||
</contexts>
|
||||
</kindred>
|
||||
```
|
||||
|
||||
All child elements are optional. An empty `<kindred/>` element is valid and signals that the addon is Kindred-aware with all defaults.
|
||||
|
||||
### Version fields
|
||||
|
||||
`min_create_version` and `max_create_version` are compared against the running Kindred Create version using semantic versioning (major.minor.patch). If the running version falls outside the declared range, the addon is skipped with a warning in the report view.
|
||||
|
||||
### Load priority
|
||||
|
||||
When multiple addons have no dependency relationship, `load_priority` determines their relative order. Lower values load first. Suggested ranges:
|
||||
|
||||
| Range | Use |
|
||||
|---|---|
|
||||
| 0-9 | SDK and core infrastructure |
|
||||
| 10-49 | Foundation addons that others may depend on |
|
||||
| 50-99 | Standard addons |
|
||||
| 100+ | Optional or late-loading addons |
|
||||
|
||||
### Dependencies
|
||||
|
||||
Each `<dependency>` names another addon by its `<name>` element in `package.xml`. The loader resolves load order using topological sort. If a dependency is not found among discovered addons, the dependent addon is skipped.
|
||||
|
||||
### Contexts
|
||||
|
||||
The `<contexts>` element documents which editing contexts the addon interacts with. The `action` attribute describes the type of interaction:
|
||||
|
||||
| Action | Meaning |
|
||||
|---|---|
|
||||
| `inject` | Addon injects commands into this context's toolbars |
|
||||
| `register` | Addon registers this as a new context |
|
||||
| `overlay` | Addon registers an overlay that may apply across contexts |
|
||||
|
||||
A wildcard `id="*"` indicates the addon's overlay applies universally (matched by a condition function rather than a specific context ID).
|
||||
|
||||
## Example: complete package.xml
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package format="1" xmlns="https://wiki.freecad.org/Package_Metadata">
|
||||
<name>MyAddon</name>
|
||||
<description>Example Kindred Create addon</description>
|
||||
<version>0.2.0</version>
|
||||
<maintainer email="dev@example.com">Developer</maintainer>
|
||||
<license>LGPL-2.1-or-later</license>
|
||||
<url type="repository">https://git.example.com/myaddon</url>
|
||||
|
||||
<content>
|
||||
<workbench>
|
||||
<classname>MyAddonWorkbench</classname>
|
||||
<subdirectory>./</subdirectory>
|
||||
</workbench>
|
||||
</content>
|
||||
|
||||
<kindred>
|
||||
<min_create_version>0.1.0</min_create_version>
|
||||
<load_priority>80</load_priority>
|
||||
<pure_python>true</pure_python>
|
||||
<contexts>
|
||||
<context id="partdesign.body" action="inject"/>
|
||||
</contexts>
|
||||
</kindred>
|
||||
</package>
|
||||
```
|
||||
|
||||
## Backward compatibility
|
||||
|
||||
- The `<kindred>` element sits outside `<content>` and is not part of FreeCAD's package.xml specification. FreeCAD's `App.Metadata` C++ parser and the AddonManager's Python `MetadataReader` both ignore unknown elements.
|
||||
- An addon installed in stock FreeCAD will work normally; the `<kindred>` extensions are simply unused.
|
||||
- The Kindred Create loader works with or without the `<kindred>` element. Addons that omit it load with no version constraints and default priority (100).
|
||||
@@ -20,7 +20,10 @@ create/
|
||||
├── mods/ # Kindred addon workbenches (submodules)
|
||||
│ ├── ztools/ # ztools workbench
|
||||
│ └── silo/ # Silo parts database
|
||||
├── kindred-icons/ # SVG icon library (~200 icons)
|
||||
├── icons/ # Icon theming (kindred overrides, palettes, retheme script)
|
||||
│ ├── kindred/ # Hand-crafted Catppuccin Mocha SVG overrides (~1444 icons)
|
||||
│ ├── mappings/ # Color palette CSVs (FCAD.csv, kindred.csv)
|
||||
│ └── retheme.py # Script to remap upstream icon colors
|
||||
├── resources/ # Branding, desktop integration
|
||||
│ ├── branding/ # Logo, splash, icon generation scripts
|
||||
│ └── icons/ # Platform icons (.ico, .icns, hicolor)
|
||||
|
||||
132
docs/src/reference/create-module-bootstrap.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Create Module Bootstrap Sequence
|
||||
|
||||
The Create module (`src/Mod/Create/`) is the integration layer that bootstraps Kindred Create's addons and deferred services. It runs in two phases: console (headless) and GUI.
|
||||
|
||||
**Source files:**
|
||||
|
||||
- `src/Mod/Create/Init.py` -- console-phase addon loading
|
||||
- `src/Mod/Create/InitGui.py` -- GUI-phase workbench loading and deferred timers
|
||||
- `src/Mod/Create/update_checker.py` -- Gitea releases API polling
|
||||
- `src/Mod/Create/kc_format.py` -- .kc file format round-trip preservation
|
||||
|
||||
## Loading Mechanism
|
||||
|
||||
FreeCAD loads module `Init.py` and `InitGui.py` files using **direct `exec()`**, not Python's import system. The C++ startup code scans `Mod/` directories, reads each file as text, compiles it, and executes it in an isolated namespace:
|
||||
|
||||
```python
|
||||
source = init_py.read_text(encoding="utf-8")
|
||||
code = compile(source, init_py, "exec")
|
||||
exec(code)
|
||||
```
|
||||
|
||||
Modules loaded this way are **not** added to `sys.modules`. Each execution gets a fresh globals dict with no caching or dependency resolution.
|
||||
|
||||
## Phase 1: Console (`Init.py`)
|
||||
|
||||
Runs immediately at application startup, before any GUI is available.
|
||||
|
||||
`setup_kindred_addons()` discovers and loads two built-in addons from `mods/`:
|
||||
|
||||
| Addon | Path | Purpose |
|
||||
|-------|------|---------|
|
||||
| ztools | `mods/ztools/ztools/` | Part design, assembly, and sketcher tools |
|
||||
| silo | `mods/silo/freecad/` | Database integration and version control |
|
||||
|
||||
For each addon:
|
||||
|
||||
1. Build the path from `FreeCAD.getHomePath() + "mods/" + addon_path`
|
||||
2. Add to `sys.path` if not already present
|
||||
3. Find `Init.py` in the addon directory
|
||||
4. Execute it with `exec(compile(source, init_file, "exec"), exec_globals)`
|
||||
|
||||
Failures are logged to `FreeCAD.Console.PrintWarning()` and do not prevent other addons from loading.
|
||||
|
||||
## Phase 2: GUI (`InitGui.py`)
|
||||
|
||||
Runs after the console phase, when `FreeCADGui` is available.
|
||||
|
||||
### Synchronous
|
||||
|
||||
`setup_kindred_workbenches()` loads `InitGui.py` from the same two addons (ztools, silo), registering their workbenches and GUI commands.
|
||||
|
||||
### Deferred Timers
|
||||
|
||||
Six `QTimer.singleShot` calls stagger initialization to let the GUI event loop settle:
|
||||
|
||||
| Delay | Function | Purpose |
|
||||
|-------|----------|---------|
|
||||
| 500 ms | `_register_kc_format()` | Register .kc file format observer |
|
||||
| 1500 ms | `_register_silo_origin()` | Register Silo as a file origin |
|
||||
| 2000 ms | `_setup_silo_auth_panel()` | Dock the Database Auth panel |
|
||||
| 3000 ms | `_check_silo_first_start()` | Show settings dialog on first run |
|
||||
| 4000 ms | `_setup_silo_activity_panel()` | Dock the Database Activity panel |
|
||||
| 10000 ms | `_check_for_updates()` | Poll Gitea for new releases |
|
||||
|
||||
Every timer callback is wrapped in `try/except`. Failures log to `FreeCAD.Console.PrintLog()` and do not crash the application.
|
||||
|
||||
### Timer Details
|
||||
|
||||
**_register_kc_format (500 ms)** -- Imports `kc_format` and calls `kc_format.register()`, which installs a `DocumentObserver` with `slotStartSaveDocument` / `slotFinishSaveDocument` hooks. These cache `silo/` ZIP entries before FreeCAD's C++ save rewrites the archive, then re-inject them afterwards. Only processes `.kc` files.
|
||||
|
||||
**_register_silo_origin (1500 ms)** -- Imports `silo_origin` and calls `silo_origin.register_silo_origin()`, making Silo available in the origin selector dropdown alongside LocalFileOrigin.
|
||||
|
||||
**_setup_silo_auth_panel (2000 ms)** -- Creates a `QDockWidget` titled "Database Auth" containing a `SiloAuthDockWidget` from `silo_commands`. Docked on the right side of the main window. Guards against duplicates by checking if the widget already exists.
|
||||
|
||||
**_check_silo_first_start (3000 ms)** -- Reads `User parameter:BaseApp/Preferences/Mod/KindredSilo`. On the very first launch (when `FirstStartChecked` is not set), runs the `Silo_Settings` command if no API URL is configured.
|
||||
|
||||
**_setup_silo_activity_panel (4000 ms)** -- Creates a "Database Activity" dock widget showing the 20 most recent Silo items (part number, description, date). Falls back to "(Unable to connect to Silo database)" on connection failure.
|
||||
|
||||
**_check_for_updates (10000 ms)** -- Calls `update_checker._run_update_check()` in the background.
|
||||
|
||||
## Update Checker
|
||||
|
||||
`update_checker.py` polls the Gitea releases API for newer versions.
|
||||
|
||||
### Check Decision (`_should_check`)
|
||||
|
||||
Reads preferences from `User parameter:BaseApp/Preferences/Mod/KindredCreate/Update`:
|
||||
|
||||
| Parameter | Type | Default | Purpose |
|
||||
|-----------|------|---------|---------|
|
||||
| `CheckEnabled` | bool | true | Master enable/disable |
|
||||
| `CheckIntervalDays` | int | 1 | Minimum days between checks |
|
||||
| `LastCheckTimestamp` | string | (none) | ISO timestamp of last check |
|
||||
| `SkippedVersion` | string | (none) | Version the user chose to skip |
|
||||
|
||||
A check runs only if enabled, the interval has elapsed, and the current version is not the skipped version.
|
||||
|
||||
### Check Execution (`check_for_update`)
|
||||
|
||||
1. Query `https://git.kindred-systems.com/api/v1/repos/kindred/create/releases?limit=10` (5 s timeout)
|
||||
2. Filter out drafts, pre-releases, and the "latest" tag
|
||||
3. Parse version tags (`v0.1.3` becomes tuple `(0, 1, 3)`)
|
||||
4. Compare against `version.VERSION` from the Create module
|
||||
5. If a newer version exists, log it to the console
|
||||
6. Record `LastCheckTimestamp`
|
||||
|
||||
The checker never shows a dialog -- it only logs to `FreeCAD.Console`.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
FreeCAD startup
|
||||
|
|
||||
Init.py (exec'd, immediate)
|
||||
+-- setup_kindred_addons()
|
||||
| +-- ztools/Init.py (exec'd)
|
||||
| +-- silo/freecad/Init.py (exec'd)
|
||||
|
|
||||
[GUI startup]
|
||||
|
|
||||
InitGui.py (exec'd, immediate)
|
||||
+-- setup_kindred_workbenches()
|
||||
| +-- ztools/InitGui.py (exec'd)
|
||||
| +-- silo/freecad/InitGui.py (exec'd)
|
||||
|
|
||||
+-- QTimer 500ms --> kc_format.register()
|
||||
+-- QTimer 1500ms --> silo_origin.register_silo_origin()
|
||||
+-- QTimer 2000ms --> SiloAuthDockWidget
|
||||
+-- QTimer 3000ms --> Silo first-start check
|
||||
+-- QTimer 4000ms --> Database Activity panel
|
||||
+-- QTimer 10000ms --> update_checker._run_update_check()
|
||||
```
|
||||
177
docs/src/reference/datum-creator.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Datum Creator System
|
||||
|
||||
The ZTools Datum Creator (`ZTools_DatumCreator`) creates parametric datum planes, axes, and points. It auto-detects the datum type from selected geometry and provides a unified task panel with 16 creation modes.
|
||||
|
||||
**Source files:**
|
||||
|
||||
- `mods/ztools/ztools/ztools/commands/datum_commands.py` -- UI, selection handling, mode detection
|
||||
- `mods/ztools/ztools/ztools/datums/core.py` -- geometry computation and FreeCAD object creation
|
||||
|
||||
## Geometry Classification
|
||||
|
||||
The `SelectionItem` class wraps a selected geometry element and classifies it into one of seven types:
|
||||
|
||||
| Type | Detection | Icon |
|
||||
|------|-----------|------|
|
||||
| face | Planar `Part.Face` or object with "Plane" in TypeId | ▢ |
|
||||
| plane | Datum plane objects or planar faces | ▣ |
|
||||
| cylinder | `Part.Face` with `Surface.Cylinder` | ◎ |
|
||||
| edge | `Part.Edge` with `Part.Line` curve | ― |
|
||||
| circle | `Part.Edge` with `Part.Circle` or `Part.ArcOfCircle` | ○ |
|
||||
| vertex | `Part.Vertex` | • |
|
||||
| unknown | Unclassified geometry | ? |
|
||||
|
||||
Classification flow:
|
||||
|
||||
1. Extract shape from object using the sub-element name (Face#, Edge#, Vertex#)
|
||||
2. Check shape type (Face, Edge, Vertex)
|
||||
3. For faces: check `surface.isPlanar()` or `isinstance(surface, Part.Cylinder)`
|
||||
4. For edges: check curve type (Line, Circle, ArcOfCircle)
|
||||
5. Fall back to `unknown`
|
||||
|
||||
## Creation Modes
|
||||
|
||||
### Planes (7 modes)
|
||||
|
||||
| Mode | Required Selection | Parameters | Description |
|
||||
|------|--------------------|------------|-------------|
|
||||
| `offset_face` | 1 face | distance (mm) | Plane parallel to face at offset |
|
||||
| `offset_plane` | 1 plane | distance (mm) | Plane parallel to datum plane at offset |
|
||||
| `midplane` | 2 faces | -- | Plane halfway between two parallel faces |
|
||||
| `3_points` | 3 vertices | -- | Plane through three non-collinear points |
|
||||
| `normal_edge` | 1 edge | position (0--1) | Plane perpendicular to edge at parameter |
|
||||
| `angled` | 1 face + 1 edge | angle (deg) | Plane at angle to face, rotating about edge |
|
||||
| `tangent_cyl` | 1 cylinder | angle (deg) | Plane tangent to cylinder at angular position |
|
||||
|
||||
### Axes (4 modes)
|
||||
|
||||
| Mode | Required Selection | Parameters | Description |
|
||||
|------|--------------------|------------|-------------|
|
||||
| `axis_2pt` | 2 vertices | -- | Axis through two points |
|
||||
| `axis_edge` | 1 edge | -- | Axis along linear edge |
|
||||
| `axis_cyl` | 1 cylinder | -- | Axis along cylinder centerline |
|
||||
| `axis_intersect` | 2 planes | -- | Axis at intersection of two planes |
|
||||
|
||||
### Points (5 modes)
|
||||
|
||||
| Mode | Required Selection | Parameters | Description |
|
||||
|------|--------------------|------------|-------------|
|
||||
| `point_vertex` | 1 vertex | -- | Point at vertex location |
|
||||
| `point_xyz` | (none) | x, y, z (mm) | Point at explicit coordinates |
|
||||
| `point_edge` | 1 edge | position (0--1) | Point at parameter location on edge |
|
||||
| `point_face` | 1 face | -- | Point at center of mass of face |
|
||||
| `point_circle` | 1 circle | -- | Point at center of circular edge |
|
||||
|
||||
## Auto-Detection Algorithm
|
||||
|
||||
The `_match_score()` method scores how well the current selection matches each mode's required types.
|
||||
|
||||
**Scoring:**
|
||||
|
||||
1. If the selection has fewer items than required, score is **0** (no match).
|
||||
2. For each required type, find a matching selected type using fuzzy matching:
|
||||
- `face` requirement matches `face` or `cylinder`
|
||||
- `edge` requirement matches `edge` or `circle`
|
||||
- All other types require exact match
|
||||
3. Score calculation:
|
||||
- **Exact cardinality** (selection count == required count): score = `100 + matched_count`
|
||||
- **Over-selected** (more items than required): score = `matched_count`
|
||||
- **No match**: score = `0`
|
||||
|
||||
The mode with the highest score wins. On each selection change, `update_mode_from_selection()` re-evaluates all 16 modes and activates the best match.
|
||||
|
||||
The detected mode is displayed with a category color:
|
||||
|
||||
- Planes: Mauve (#cba6f7)
|
||||
- Axes: Teal (#94e2d5)
|
||||
- Points: Yellow (#f9e2af)
|
||||
|
||||
## Task Panel UI
|
||||
|
||||
```
|
||||
+-------------------------------------+
|
||||
| ZTools Datum Creator |
|
||||
+-------------------------------------+
|
||||
| Selection |
|
||||
| [icon] Element Name [Remove] |
|
||||
| [Add Selected] [Remove] [Clear] |
|
||||
+-------------------------------------+
|
||||
| Datum Type |
|
||||
| DETECTED MODE (colored) |
|
||||
| Override: [dropdown] |
|
||||
+-------------------------------------+
|
||||
| Parameters (dynamic per mode) |
|
||||
| Offset: [spinner] mm |
|
||||
| Angle: [spinner] deg |
|
||||
| Position: [spinner] 0-1 |
|
||||
| X/Y/Z: [spinner] mm |
|
||||
+-------------------------------------+
|
||||
| Options |
|
||||
| [ ] Link to Spreadsheet |
|
||||
| [x] Add to Active Body |
|
||||
| [ ] Custom Name: [text] |
|
||||
+-------------------------------------+
|
||||
| [OK] [Cancel] |
|
||||
+-------------------------------------+
|
||||
```
|
||||
|
||||
### Selection table
|
||||
|
||||
Three columns: type icon (28px), element name (stretch), remove button (28px). Duplicates are rejected. A FreeCAD `SelectionObserver` keeps the "Add Selected" button state synchronized with the active 3D selection.
|
||||
|
||||
### Mode override
|
||||
|
||||
The dropdown lists all 16 modes prefixed by category (`[P]` plane, `[A]` axis, `[Pt]` point). Selecting a mode disables auto-detection until "(Auto-detect)" is re-selected.
|
||||
|
||||
### Parameters section
|
||||
|
||||
Rebuilt dynamically when the mode changes. Only the parameter widgets relevant to the active mode are shown. Modes with no parameters hide the section entirely.
|
||||
|
||||
### Options
|
||||
|
||||
- **Link to Spreadsheet**: creates a spreadsheet alias and expression-links the datum parameter (offset, angle, coordinates) for parametric control.
|
||||
- **Add to Active Body**: when checked, creates a `PartDesign::Plane/Line/Point` inside the active body. When unchecked, creates a document-level `Part::Plane/Line/Vertex`.
|
||||
- **Custom Name**: overrides the auto-generated name (format: `ZPlane_Offset_001`).
|
||||
|
||||
## Dispatch to core.py
|
||||
|
||||
`DatumCreatorTaskPanel.accept()` calls `create_datum()`, which:
|
||||
|
||||
1. Reads the current mode, body, name, and parameters from the UI
|
||||
2. Extracts `SelectionItem` objects by type
|
||||
3. Dispatches to the corresponding `core.*` function:
|
||||
|
||||
| Mode | Core function |
|
||||
|------|---------------|
|
||||
| `offset_face` | `core.plane_offset_from_face(face, distance, ...)` |
|
||||
| `offset_plane` | `core.plane_offset_from_plane(plane, distance, ...)` |
|
||||
| `midplane` | `core.plane_midplane(face1, face2, ...)` |
|
||||
| `3_points` | `core.plane_from_3_points(p1, p2, p3, ...)` |
|
||||
| `normal_edge` | `core.plane_normal_to_edge(edge, parameter, ...)` |
|
||||
| `angled` | `core.plane_angled(face, edge, angle, ...)` |
|
||||
| `tangent_cyl` | `core.plane_tangent_to_cylinder(face, angle, ...)` |
|
||||
| `axis_2pt` | `core.axis_from_2_points(p1, p2, ...)` |
|
||||
| `axis_edge` | `core.axis_from_edge(edge, ...)` |
|
||||
| `axis_cyl` | `core.axis_cylinder_center(face, ...)` |
|
||||
| `axis_intersect` | `core.axis_intersection_planes(plane1, plane2, ...)` |
|
||||
| `point_vertex` | `core.point_at_vertex(vertex, ...)` |
|
||||
| `point_xyz` | `core.point_at_coordinates(x, y, z, ...)` |
|
||||
| `point_edge` | `core.point_on_edge(edge, parameter, ...)` |
|
||||
| `point_face` | `core.point_center_of_face(face, ...)` |
|
||||
| `point_circle` | `core.point_center_of_circle(edge, ...)` |
|
||||
|
||||
## Core Implementation
|
||||
|
||||
Each `core.*` function:
|
||||
|
||||
1. Creates the FreeCAD object (`PartDesign::Plane` in a body, `Part::Plane` at document level)
|
||||
2. Computes the placement from the source geometry
|
||||
3. Configures attachment (MapMode, AttachmentSupport, offset) for parametric updates
|
||||
4. Stores ZTools metadata in custom properties:
|
||||
- `ZTools_Type` -- creation method identifier (e.g. `"offset_from_face"`)
|
||||
- `ZTools_Params` -- parameters as JSON (e.g. `{"distance": 10}`)
|
||||
- `ZTools_SourceRefs` -- source geometry references as JSON
|
||||
5. Applies Catppuccin Mocha styling (mauve at 70% transparency for planes)
|
||||
6. Optionally links parameters to a spreadsheet alias
|
||||
|
||||
Auto-naming uses the format `ZPlane_Offset_001`, incrementing the index for each new datum of the same type.
|
||||
@@ -73,25 +73,27 @@ database:
|
||||
|
||||
---
|
||||
|
||||
## Storage (MinIO/S3)
|
||||
## Storage (Filesystem)
|
||||
|
||||
| Key | Type | Default | Env Override | Description |
|
||||
|-----|------|---------|-------------|-------------|
|
||||
| `storage.endpoint` | string | — | `SILO_MINIO_ENDPOINT` | MinIO/S3 endpoint (`host:port`) |
|
||||
| `storage.access_key` | string | — | `SILO_MINIO_ACCESS_KEY` | Access key |
|
||||
| `storage.secret_key` | string | — | `SILO_MINIO_SECRET_KEY` | Secret key |
|
||||
| `storage.bucket` | string | — | — | S3 bucket name (created automatically if missing) |
|
||||
| `storage.use_ssl` | bool | `false` | — | Use HTTPS for MinIO connections |
|
||||
| `storage.region` | string | `"us-east-1"` | — | S3 region |
|
||||
Files are stored on the local filesystem under a configurable root directory.
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `storage.backend` | string | `"filesystem"` | Storage backend (`filesystem`) |
|
||||
| `storage.filesystem.root_dir` | string | — | Root directory for file storage (required) |
|
||||
|
||||
```yaml
|
||||
storage:
|
||||
endpoint: "localhost:9000"
|
||||
access_key: "" # use SILO_MINIO_ACCESS_KEY env var
|
||||
secret_key: "" # use SILO_MINIO_SECRET_KEY env var
|
||||
bucket: "silo-files"
|
||||
use_ssl: false
|
||||
region: "us-east-1"
|
||||
backend: "filesystem"
|
||||
filesystem:
|
||||
root_dir: "/opt/silo/data"
|
||||
```
|
||||
|
||||
Ensure the directory exists and is writable by the `silo` user:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/silo/data
|
||||
sudo chown silo:silo /opt/silo/data
|
||||
```
|
||||
|
||||
---
|
||||
@@ -264,9 +266,6 @@ All environment variable overrides. These take precedence over values in `config
|
||||
| `SILO_DB_NAME` | `database.name` | PostgreSQL database name |
|
||||
| `SILO_DB_USER` | `database.user` | PostgreSQL user |
|
||||
| `SILO_DB_PASSWORD` | `database.password` | PostgreSQL password |
|
||||
| `SILO_MINIO_ENDPOINT` | `storage.endpoint` | MinIO endpoint |
|
||||
| `SILO_MINIO_ACCESS_KEY` | `storage.access_key` | MinIO access key |
|
||||
| `SILO_MINIO_SECRET_KEY` | `storage.secret_key` | MinIO secret key |
|
||||
| `SILO_SESSION_SECRET` | `auth.session_secret` | Session cookie signing secret |
|
||||
| `SILO_ADMIN_USERNAME` | `auth.local.default_admin_username` | Default admin username |
|
||||
| `SILO_ADMIN_PASSWORD` | `auth.local.default_admin_password` | Default admin password |
|
||||
@@ -296,11 +295,9 @@ database:
|
||||
sslmode: "disable"
|
||||
|
||||
storage:
|
||||
endpoint: "localhost:9000"
|
||||
access_key: "minioadmin"
|
||||
secret_key: "minioadmin"
|
||||
bucket: "silo-files"
|
||||
use_ssl: false
|
||||
backend: "filesystem"
|
||||
filesystem:
|
||||
root_dir: "./data"
|
||||
|
||||
schemas:
|
||||
directory: "./schemas"
|
||||
|
||||
246
docs/src/silo-server/DAG.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Dependency DAG Specification
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
The Dependency DAG is a server-side graph that tracks how features, constraints, and assembly relationships depend on each other. It enables three capabilities described in [MULTI_USER_EDITS.md](MULTI_USER_EDITS.md):
|
||||
|
||||
1. **Interference detection** -- comparing dependency cones of concurrent edit sessions to classify conflicts as none, soft, or hard before the user encounters them.
|
||||
2. **Incremental validation** -- marking changed nodes dirty and propagating only through the affected subgraph, using input-hash memoization to stop early when inputs haven't changed.
|
||||
3. **Structured merge safety** -- walking the DAG to determine whether concurrent edits share upstream dependencies, deciding if auto-merge is safe or manual review is required.
|
||||
|
||||
---
|
||||
|
||||
## 2. Two-Tier Model
|
||||
|
||||
Silo maintains two levels of dependency graph:
|
||||
|
||||
### 2.1 BOM DAG (existing)
|
||||
|
||||
The assembly-to-part relationship graph already stored in the `relationships` table. Each row represents a parent item containing a child item with a quantity and relationship type (`component`, `alternate`, `reference`). This graph is queried via `GetBOM`, `GetExpandedBOM`, `GetWhereUsed`, and `HasCycle` in `internal/db/relationships.go`.
|
||||
|
||||
The BOM DAG is **not modified** by this specification. It continues to serve its existing purpose.
|
||||
|
||||
### 2.2 Feature DAG (new)
|
||||
|
||||
A finer-grained graph stored in `dag_nodes` and `dag_edges` tables. Each node represents a feature within a single item's revision -- a sketch, pad, fillet, pocket, constraint, body, or part-level container. Edges represent "depends on" relationships: if Pad003 depends on Sketch001, an edge runs from Sketch001 to Pad003.
|
||||
|
||||
The feature DAG is populated by clients (silo-mod) when users save, or by runners after compute jobs. Silo stores and queries it but does not generate it -- the Create client has access to the feature tree and is the authoritative source.
|
||||
|
||||
### 2.3 Cross-Item Edges
|
||||
|
||||
Assembly constraints often reference geometry on child parts (e.g., "mate Face6 of PartA to Face2 of PartB"). These cross-item dependencies are stored in `dag_cross_edges`, linking a node in one item to a node in another. Each cross-edge optionally references the `relationships` row that establishes the BOM connection.
|
||||
|
||||
---
|
||||
|
||||
## 3. Data Model
|
||||
|
||||
### 3.1 dag_nodes
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `id` | UUID | Primary key |
|
||||
| `item_id` | UUID | FK to `items.id` |
|
||||
| `revision_number` | INTEGER | Revision this DAG snapshot belongs to |
|
||||
| `node_key` | TEXT | Feature name from Create (e.g., `Sketch001`, `Pad003`, `Body`) |
|
||||
| `node_type` | TEXT | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`, `mirror`, `pattern`, `boolean` |
|
||||
| `properties_hash` | TEXT | SHA-256 of the node's parametric inputs (sketch coordinates, fillet radius, constraint values). Used for memoization -- if the hash hasn't changed, validation can skip this node. |
|
||||
| `validation_state` | TEXT | One of: `clean`, `dirty`, `validating`, `failed` |
|
||||
| `validation_msg` | TEXT | Error message when `validation_state = 'failed'` |
|
||||
| `metadata` | JSONB | Type-specific data (sketch coords, feature params, constraint definitions) |
|
||||
| `created_at` | TIMESTAMPTZ | Row creation time |
|
||||
| `updated_at` | TIMESTAMPTZ | Last state change |
|
||||
|
||||
**Uniqueness:** `(item_id, revision_number, node_key)` -- one node per feature per revision.
|
||||
|
||||
### 3.2 dag_edges
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `id` | UUID | Primary key |
|
||||
| `source_node_id` | UUID | FK to `dag_nodes.id` -- the upstream node |
|
||||
| `target_node_id` | UUID | FK to `dag_nodes.id` -- the downstream node that depends on source |
|
||||
| `edge_type` | TEXT | `depends_on` (default), `references`, `constrains` |
|
||||
| `metadata` | JSONB | Optional edge metadata |
|
||||
|
||||
**Direction convention:** An edge from A to B means "B depends on A". A is upstream, B is downstream. Forward-cone traversal from A walks edges where A is the source.
|
||||
|
||||
**Uniqueness:** `(source_node_id, target_node_id, edge_type)`.
|
||||
|
||||
**Constraint:** `source_node_id != target_node_id` (no self-edges).
|
||||
|
||||
### 3.3 dag_cross_edges
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `id` | UUID | Primary key |
|
||||
| `source_node_id` | UUID | FK to `dag_nodes.id` -- node in item A |
|
||||
| `target_node_id` | UUID | FK to `dag_nodes.id` -- node in item B |
|
||||
| `relationship_id` | UUID | FK to `relationships.id` (nullable) -- the BOM entry connecting the two items |
|
||||
| `edge_type` | TEXT | `assembly_ref` (default) |
|
||||
| `metadata` | JSONB | Reference details (face ID, edge ID, etc.) |
|
||||
|
||||
**Uniqueness:** `(source_node_id, target_node_id)`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Validation States
|
||||
|
||||
Each node has a `validation_state` that tracks whether its computed geometry is current:
|
||||
|
||||
| State | Meaning |
|
||||
|-------|---------|
|
||||
| `clean` | Node's geometry matches its `properties_hash`. No recompute needed. |
|
||||
| `dirty` | An upstream change has propagated to this node. Recompute required. |
|
||||
| `validating` | A compute job is currently revalidating this node. |
|
||||
| `failed` | Recompute failed. `validation_msg` contains the error. |
|
||||
|
||||
### 4.1 State Transitions
|
||||
|
||||
```
|
||||
clean → dirty (upstream change detected, or MarkDirty called)
|
||||
dirty → validating (compute job claims this node)
|
||||
validating → clean (recompute succeeded, properties_hash updated)
|
||||
validating → failed (recompute produced an error)
|
||||
failed → dirty (upstream change detected, retry possible)
|
||||
dirty → clean (properties_hash matches previous -- memoization shortcut)
|
||||
```
|
||||
|
||||
### 4.2 Dirty Propagation
|
||||
|
||||
When a node is marked dirty, all downstream nodes in its forward cone are also marked dirty. This is done atomically in a single recursive CTE:
|
||||
|
||||
```sql
|
||||
WITH RECURSIVE forward_cone AS (
|
||||
SELECT $1::uuid AS node_id
|
||||
UNION
|
||||
SELECT e.target_node_id
|
||||
FROM dag_edges e
|
||||
JOIN forward_cone fc ON fc.node_id = e.source_node_id
|
||||
)
|
||||
UPDATE dag_nodes SET validation_state = 'dirty', updated_at = now()
|
||||
WHERE id IN (SELECT node_id FROM forward_cone)
|
||||
AND validation_state = 'clean';
|
||||
```
|
||||
|
||||
### 4.3 Memoization
|
||||
|
||||
Before marking a node dirty, the system can compare the new `properties_hash` against the stored value. If they match, the change did not affect this node's inputs, and propagation stops. This is the memoization boundary described in MULTI_USER_EDITS.md Section 5.2.
|
||||
|
||||
---
|
||||
|
||||
## 5. Graph Queries
|
||||
|
||||
### 5.1 Forward Cone
|
||||
|
||||
Returns all nodes downstream of a given node -- everything that would be affected if the source node changes. Used for interference detection: if two users' forward cones overlap, there is potential interference.
|
||||
|
||||
```sql
|
||||
WITH RECURSIVE forward_cone AS (
|
||||
SELECT target_node_id AS node_id
|
||||
FROM dag_edges WHERE source_node_id = $1
|
||||
UNION
|
||||
SELECT e.target_node_id
|
||||
FROM dag_edges e
|
||||
JOIN forward_cone fc ON fc.node_id = e.source_node_id
|
||||
)
|
||||
SELECT n.* FROM dag_nodes n JOIN forward_cone fc ON n.id = fc.node_id;
|
||||
```
|
||||
|
||||
### 5.2 Backward Cone
|
||||
|
||||
Returns all nodes upstream of a given node -- everything the target node depends on.
|
||||
|
||||
### 5.3 Dirty Subgraph
|
||||
|
||||
Returns all nodes for a given item where `validation_state != 'clean'`, along with their edges. This is the input to an incremental validation job.
|
||||
|
||||
### 5.4 Cycle Detection
|
||||
|
||||
Before adding an edge, check that it would not create a cycle. Uses the same recursive ancestor-walk pattern as `HasCycle` in `internal/db/relationships.go`.
|
||||
|
||||
---
|
||||
|
||||
## 6. DAG Sync
|
||||
|
||||
Clients push the full feature DAG to Silo via `PUT /api/items/{partNumber}/dag`. The sync payload is a JSON document:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"key": "Sketch001",
|
||||
"type": "sketch",
|
||||
"properties_hash": "a1b2c3...",
|
||||
"metadata": {
|
||||
"coordinates": [[0, 0], [10, 0], [10, 5]],
|
||||
"constraints": ["horizontal", "vertical"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "Pad003",
|
||||
"type": "pad",
|
||||
"properties_hash": "d4e5f6...",
|
||||
"metadata": {
|
||||
"length": 15.0,
|
||||
"direction": [0, 0, 1]
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "Sketch001",
|
||||
"target": "Pad003",
|
||||
"type": "depends_on"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The server processes this within a single transaction:
|
||||
1. Upsert all nodes (matched by `item_id + revision_number + node_key`).
|
||||
2. Replace all edges for this item/revision.
|
||||
3. Compare new `properties_hash` values against stored values to detect changes.
|
||||
4. Mark changed nodes and their forward cones dirty.
|
||||
5. Publish `dag.updated` SSE event.
|
||||
|
||||
---
|
||||
|
||||
## 7. Interference Detection
|
||||
|
||||
When a user registers an edit context (MULTI_USER_EDITS.md Section 3.1), the server:
|
||||
|
||||
1. Looks up the node(s) being edited by `node_key` within the item's current revision.
|
||||
2. Computes the forward cone for those nodes.
|
||||
3. Compares the cone against all active edit sessions' cones.
|
||||
4. Classifies interference:
|
||||
- **No overlap** → no interference, fully concurrent.
|
||||
- **Overlap, different objects** → soft interference, visual indicator via SSE.
|
||||
- **Same object, same edit type** → hard interference, edit blocked.
|
||||
|
||||
---
|
||||
|
||||
## 8. REST API
|
||||
|
||||
All endpoints are under `/api/items/{partNumber}` and require authentication.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/dag` | viewer | Get full feature DAG for current revision |
|
||||
| `GET` | `/dag/forward-cone/{nodeKey}` | viewer | Get forward dependency cone |
|
||||
| `GET` | `/dag/dirty` | viewer | Get dirty subgraph |
|
||||
| `PUT` | `/dag` | editor | Sync full feature tree (from client or runner) |
|
||||
| `POST` | `/dag/mark-dirty/{nodeKey}` | editor | Manually mark a node and its cone dirty |
|
||||
|
||||
---
|
||||
|
||||
## 9. References
|
||||
|
||||
- [MULTI_USER_EDITS.md](MULTI_USER_EDITS.md) -- Full multi-user editing specification
|
||||
- [WORKERS.md](WORKERS.md) -- Worker/runner system that executes validation jobs
|
||||
- [ROADMAP.md](ROADMAP.md) -- Tier 0 Dependency DAG entry
|
||||
395
docs/src/silo-server/DAG_CLIENT_INTEGRATION.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# DAG Client Integration Contract
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
This document describes what silo-mod and Headless Create runners need to implement to integrate with the Silo dependency DAG and worker system.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The DAG system has two client-side integration points:
|
||||
|
||||
1. **silo-mod workbench** (desktop) -- pushes DAG data to Silo on save or revision create.
|
||||
2. **silorunner + silo-mod** (headless) -- extracts DAGs, validates features, and exports geometry as compute jobs.
|
||||
|
||||
Both share the same Python codebase in the silo-mod repository. Desktop users call the code interactively; runners call it headlessly via `create --console`.
|
||||
|
||||
---
|
||||
|
||||
## 2. DAG Sync Payload
|
||||
|
||||
Clients push feature trees to Silo via:
|
||||
|
||||
```
|
||||
PUT /api/items/{partNumber}/dag
|
||||
Authorization: Bearer <user_token or runner_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### 2.1 Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Sketch001",
|
||||
"node_type": "sketch",
|
||||
"properties_hash": "a1b2c3d4e5f6...",
|
||||
"metadata": {
|
||||
"label": "Base Profile",
|
||||
"constraint_count": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"node_type": "pad",
|
||||
"properties_hash": "f6e5d4c3b2a1...",
|
||||
"metadata": {
|
||||
"label": "Main Extrusion",
|
||||
"length": 25.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source_key": "Sketch001",
|
||||
"target_key": "Pad001",
|
||||
"edge_type": "depends_on"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Field Reference
|
||||
|
||||
**Nodes:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `node_key` | string | yes | Unique within item+revision. Use Create's internal object name (e.g. `Sketch001`, `Pad003`). |
|
||||
| `node_type` | string | yes | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`. |
|
||||
| `properties_hash` | string | no | SHA-256 hex digest of the node's parametric inputs. Used for memoization. |
|
||||
| `validation_state` | string | no | One of: `clean`, `dirty`, `validating`, `failed`. Defaults to `clean`. |
|
||||
| `metadata` | object | no | Arbitrary key-value pairs for display or debugging. |
|
||||
|
||||
**Edges:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `source_key` | string | yes | The node that is depended upon. |
|
||||
| `target_key` | string | yes | The node that depends on the source. |
|
||||
| `edge_type` | string | no | One of: `depends_on` (default), `references`, `constrains`. |
|
||||
|
||||
**Direction convention:** Edges point from dependency to dependent. If Pad001 depends on Sketch001, the edge is `source_key: "Sketch001"`, `target_key: "Pad001"`.
|
||||
|
||||
### 2.3 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"synced": true,
|
||||
"node_count": 15,
|
||||
"edge_count": 14
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Computing properties_hash
|
||||
|
||||
The `properties_hash` enables memoization -- if a node's inputs haven't changed since the last validation, it can be skipped. Computing it:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
def compute_properties_hash(feature_obj):
|
||||
"""Hash the parametric inputs of a Create feature."""
|
||||
inputs = {}
|
||||
|
||||
if feature_obj.TypeId == "Sketcher::SketchObject":
|
||||
# Hash geometry + constraints
|
||||
inputs["geometry_count"] = feature_obj.GeometryCount
|
||||
inputs["constraint_count"] = feature_obj.ConstraintCount
|
||||
inputs["geometry"] = str(feature_obj.Shape.exportBrep())
|
||||
elif feature_obj.TypeId == "PartDesign::Pad":
|
||||
inputs["length"] = feature_obj.Length.Value
|
||||
inputs["type"] = str(feature_obj.Type)
|
||||
inputs["reversed"] = feature_obj.Reversed
|
||||
inputs["sketch"] = feature_obj.Profile[0].Name
|
||||
# ... other feature types
|
||||
|
||||
canonical = json.dumps(inputs, sort_keys=True)
|
||||
return hashlib.sha256(canonical.encode()).hexdigest()
|
||||
```
|
||||
|
||||
The exact inputs per feature type are determined by what parametric values affect the feature's geometry. Include anything that, if changed, would require recomputation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Feature Tree Walking
|
||||
|
||||
To extract the DAG from a Create document:
|
||||
|
||||
```python
|
||||
import FreeCAD
|
||||
|
||||
def extract_dag(doc):
|
||||
"""Walk a Create document and return nodes + edges."""
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
for obj in doc.Objects:
|
||||
# Skip non-feature objects
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
nodes.append({
|
||||
"node_key": obj.Name,
|
||||
"node_type": node_type,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
"metadata": {
|
||||
"label": obj.Label,
|
||||
"type_id": obj.TypeId,
|
||||
}
|
||||
})
|
||||
|
||||
# Walk dependencies via InList (objects this one depends on)
|
||||
for dep in obj.InList:
|
||||
if hasattr(dep, "TypeId") and classify_type(dep.TypeId):
|
||||
edges.append({
|
||||
"source_key": dep.Name,
|
||||
"target_key": obj.Name,
|
||||
"edge_type": "depends_on",
|
||||
})
|
||||
|
||||
return nodes, edges
|
||||
|
||||
|
||||
def classify_type(type_id):
|
||||
"""Map Create TypeIds to DAG node types."""
|
||||
mapping = {
|
||||
"Sketcher::SketchObject": "sketch",
|
||||
"PartDesign::Pad": "pad",
|
||||
"PartDesign::Pocket": "pocket",
|
||||
"PartDesign::Fillet": "fillet",
|
||||
"PartDesign::Chamfer": "chamfer",
|
||||
"PartDesign::Body": "body",
|
||||
"Part::Feature": "part",
|
||||
"Sketcher::SketchConstraint": "constraint",
|
||||
}
|
||||
return mapping.get(type_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. When to Push DAG Data
|
||||
|
||||
Push the DAG to Silo in these scenarios:
|
||||
|
||||
| Event | Trigger | Who |
|
||||
|-------|---------|-----|
|
||||
| User saves in silo-mod | On save callback | Desktop silo-mod workbench |
|
||||
| User creates a revision | After `POST /api/items/{pn}/revisions` succeeds | Desktop silo-mod workbench |
|
||||
| Runner extracts DAG | After `create-dag-extract` job completes | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
| Runner validates | After `create-validate` job, push updated validation states | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Runner Entry Points
|
||||
|
||||
silo-mod must provide these Python entry points for headless invocation:
|
||||
|
||||
### 6.1 silo.runner.dag_extract
|
||||
|
||||
Extracts the feature DAG from a Create file and writes it as JSON.
|
||||
|
||||
```python
|
||||
# silo/runner.py
|
||||
|
||||
def dag_extract(input_path, output_path):
|
||||
"""
|
||||
Extract feature DAG from a Create file.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc (Kindred Create) file.
|
||||
output_path: Path to write the JSON output.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"nodes": [...], // Same format as DAG sync payload
|
||||
"edges": [...]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
nodes, edges = extract_dag(doc)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"nodes": nodes, "edges": edges}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.2 silo.runner.validate
|
||||
|
||||
Rebuilds all features and reports pass/fail per node.
|
||||
|
||||
```python
|
||||
def validate(input_path, output_path):
|
||||
"""
|
||||
Validate a Create file by rebuilding all features.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"valid": true/false,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"state": "clean", // or "failed"
|
||||
"message": null, // error message if failed
|
||||
"properties_hash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
doc.recompute()
|
||||
|
||||
results = []
|
||||
all_valid = True
|
||||
for obj in doc.Objects:
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
state = "clean"
|
||||
message = None
|
||||
if hasattr(obj, "isValid") and not obj.isValid():
|
||||
state = "failed"
|
||||
message = f"Feature {obj.Label} failed to recompute"
|
||||
all_valid = False
|
||||
|
||||
results.append({
|
||||
"node_key": obj.Name,
|
||||
"state": state,
|
||||
"message": message,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
})
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"valid": all_valid, "nodes": results}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.3 silo.runner.export
|
||||
|
||||
Exports geometry to STEP, IGES, or other formats.
|
||||
|
||||
```python
|
||||
def export(input_path, output_path, format="step"):
|
||||
"""
|
||||
Export a Create file to an external format.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc file.
|
||||
output_path: Path to write the exported file.
|
||||
format: Export format ("step", "iges", "stl", "obj").
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
|
||||
import Part
|
||||
shapes = [obj.Shape for obj in doc.Objects if hasattr(obj, "Shape")]
|
||||
compound = Part.makeCompound(shapes)
|
||||
|
||||
format_map = {
|
||||
"step": "STEP",
|
||||
"iges": "IGES",
|
||||
"stl": "STL",
|
||||
"obj": "OBJ",
|
||||
}
|
||||
|
||||
Part.export([compound], output_path)
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Headless Invocation
|
||||
|
||||
The `silorunner` binary shells out to Create (with silo-mod installed):
|
||||
|
||||
```bash
|
||||
# DAG extraction
|
||||
create --console -e "from silo.runner import dag_extract; dag_extract('/tmp/job/part.kc', '/tmp/job/dag.json')"
|
||||
|
||||
# Validation
|
||||
create --console -e "from silo.runner import validate; validate('/tmp/job/part.kc', '/tmp/job/result.json')"
|
||||
|
||||
# Export
|
||||
create --console -e "from silo.runner import export; export('/tmp/job/part.kc', '/tmp/job/output.step', 'step')"
|
||||
```
|
||||
|
||||
**Prerequisites:** The runner host must have:
|
||||
- Headless Create installed (Kindred's fork of FreeCAD)
|
||||
- silo-mod installed as a Create addon (so `from silo.runner import ...` works)
|
||||
- No display server required -- `--console` mode is headless
|
||||
|
||||
---
|
||||
|
||||
## 8. Validation Result Handling
|
||||
|
||||
After a runner completes a `create-validate` job, it should:
|
||||
|
||||
1. Read the result JSON.
|
||||
2. Push updated validation states via `PUT /api/runner/jobs/{jobID}/dag`:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{"node_key": "Sketch001", "node_type": "sketch", "validation_state": "clean", "properties_hash": "abc..."},
|
||||
{"node_key": "Pad001", "node_type": "pad", "validation_state": "failed", "properties_hash": "def..."}
|
||||
],
|
||||
"edges": [
|
||||
{"source_key": "Sketch001", "target_key": "Pad001"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Complete the job via `POST /api/runner/jobs/{jobID}/complete` with the summary result.
|
||||
|
||||
---
|
||||
|
||||
## 9. SSE Events
|
||||
|
||||
Clients should listen for these events on `GET /api/events`:
|
||||
|
||||
| Event | Payload | When |
|
||||
|-------|---------|------|
|
||||
| `dag.updated` | `{item_id, part_number, revision_number, node_count, edge_count}` | After any DAG sync |
|
||||
| `dag.validated` | `{item_id, part_number, valid, failed_count}` | After validation completes |
|
||||
| `job.created` | `{job_id, definition_name, trigger, item_id}` | Job auto-triggered or manually created |
|
||||
| `job.claimed` | `{job_id, runner_id, runner}` | Runner claims a job |
|
||||
| `job.progress` | `{job_id, progress, message}` | Runner reports progress |
|
||||
| `job.completed` | `{job_id, runner_id}` | Job finishes successfully |
|
||||
| `job.failed` | `{job_id, runner_id, error}` | Job fails |
|
||||
| `job.cancelled` | `{job_id, cancelled_by}` | Job cancelled by user |
|
||||
|
||||
---
|
||||
|
||||
## 10. Cross-Item Edges
|
||||
|
||||
For assembly constraints that reference geometry in child parts (e.g. a mate constraint between two parts), use the `dag_cross_edges` table. These edges bridge the BOM DAG and the feature DAG.
|
||||
|
||||
Cross-item edges are **not** included in the standard `PUT /dag` sync. They will be managed through a dedicated endpoint in a future iteration once the assembly constraint model in Create/silo-mod is finalized.
|
||||
|
||||
For now, the DAG sync covers intra-item dependencies only. Assembly-level interference detection uses the BOM DAG (`relationships` table) combined with per-item feature DAGs.
|
||||
@@ -4,7 +4,7 @@
|
||||
> instructions. This document covers ongoing maintenance and operations for an
|
||||
> existing deployment.
|
||||
|
||||
This guide covers deploying Silo to a dedicated VM using external PostgreSQL and MinIO services.
|
||||
This guide covers deploying Silo to a dedicated VM using external PostgreSQL and local filesystem storage.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -26,28 +26,25 @@ This guide covers deploying Silo to a dedicated VM using external PostgreSQL and
|
||||
│ │ silod │ │
|
||||
│ │ (Silo API Server) │ │
|
||||
│ │ :8080 │ │
|
||||
│ │ Files: /opt/silo/data │ │
|
||||
│ └───────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────────────┐ ┌─────────────────────────────────┐
|
||||
│ psql.example.internal │ │ minio.example.internal │
|
||||
│ PostgreSQL 16 │ │ MinIO S3 │
|
||||
│ :5432 │ │ :9000 (API) │
|
||||
│ │ │ :9001 (Console) │
|
||||
└─────────────────────────┘ └─────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────┐
|
||||
│ psql.example.internal │
|
||||
│ PostgreSQL 16 │
|
||||
│ :5432 │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
## External Services
|
||||
|
||||
The following external services are already configured:
|
||||
|
||||
| Service | Host | Database/Bucket | User |
|
||||
|---------|------|-----------------|------|
|
||||
| Service | Host | Database | User |
|
||||
|---------|------|----------|------|
|
||||
| PostgreSQL | psql.example.internal:5432 | silo | silo |
|
||||
| MinIO | minio.example.internal:9000 | silo-files | silouser |
|
||||
|
||||
Migrations have been applied to the database.
|
||||
Files are stored on the local filesystem at `/opt/silo/data`. Migrations have been applied to the database.
|
||||
|
||||
---
|
||||
|
||||
@@ -107,21 +104,15 @@ Fill in the values:
|
||||
# Database credentials (psql.example.internal)
|
||||
SILO_DB_PASSWORD=your-database-password
|
||||
|
||||
# MinIO credentials (minio.example.internal)
|
||||
SILO_MINIO_ACCESS_KEY=silouser
|
||||
SILO_MINIO_SECRET_KEY=your-minio-secret-key
|
||||
|
||||
```
|
||||
|
||||
### Verify External Services
|
||||
|
||||
Before deploying, verify connectivity to external services:
|
||||
Before deploying, verify connectivity to PostgreSQL:
|
||||
|
||||
```bash
|
||||
# Test PostgreSQL
|
||||
psql -h psql.example.internal -U silo -d silo -c 'SELECT 1'
|
||||
|
||||
# Test MinIO
|
||||
curl -I http://minio.example.internal:9000/minio/health/live
|
||||
```
|
||||
|
||||
---
|
||||
@@ -183,6 +174,7 @@ sudo -E /opt/silo/src/scripts/deploy.sh
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `/opt/silo/bin/silod` | Server binary |
|
||||
| `/opt/silo/data/` | File storage root |
|
||||
| `/opt/silo/src/` | Git repository checkout |
|
||||
| `/etc/silo/config.yaml` | Server configuration |
|
||||
| `/etc/silo/silod.env` | Environment variables (secrets) |
|
||||
@@ -242,7 +234,7 @@ sudo journalctl -u silod --since "2024-01-15 10:00:00"
|
||||
# Basic health check
|
||||
curl http://localhost:8080/health
|
||||
|
||||
# Full readiness check (includes DB and MinIO)
|
||||
# Full readiness check (includes DB)
|
||||
curl http://localhost:8080/ready
|
||||
```
|
||||
|
||||
@@ -318,24 +310,6 @@ psql -h psql.example.internal -U silo -d silo -f /opt/silo/src/migrations/008_ne
|
||||
|
||||
3. Check `pg_hba.conf` on PostgreSQL server allows connections from this host.
|
||||
|
||||
### Connection Refused to MinIO
|
||||
|
||||
1. Test network connectivity:
|
||||
```bash
|
||||
nc -zv minio.example.internal 9000
|
||||
```
|
||||
|
||||
2. Test with curl:
|
||||
```bash
|
||||
curl -I http://minio.example.internal:9000/minio/health/live
|
||||
```
|
||||
|
||||
3. Check SSL settings in config match MinIO setup:
|
||||
```yaml
|
||||
storage:
|
||||
use_ssl: true # or false
|
||||
```
|
||||
|
||||
### Health Check Fails
|
||||
|
||||
```bash
|
||||
@@ -345,7 +319,9 @@ curl -v http://localhost:8080/ready
|
||||
|
||||
# If ready fails but health passes, check external services
|
||||
psql -h psql.example.internal -U silo -d silo -c 'SELECT 1'
|
||||
curl http://minio.example.internal:9000/minio/health/live
|
||||
|
||||
# Check file storage directory
|
||||
ls -la /opt/silo/data
|
||||
```
|
||||
|
||||
### Build Fails
|
||||
@@ -460,10 +436,9 @@ sudo systemctl reload nginx
|
||||
|
||||
- [ ] `/etc/silo/silod.env` has mode 600 (`chmod 600`)
|
||||
- [ ] Database password is strong and unique
|
||||
- [ ] MinIO credentials are specific to silo (not admin)
|
||||
- [ ] SSL/TLS enabled for PostgreSQL (`sslmode: require`)
|
||||
- [ ] SSL/TLS enabled for MinIO (`use_ssl: true`) if available
|
||||
- [ ] HTTPS enabled via nginx reverse proxy
|
||||
- [ ] File storage directory (`/opt/silo/data`) owned by `silo` user with mode 750
|
||||
- [ ] Silod listens on localhost only (`host: 127.0.0.1`)
|
||||
- [ ] Firewall allows only ports 80, 443 (not 8080)
|
||||
- [ ] Service runs as non-root `silo` user
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# Silo Gap Analysis and Revision Control Roadmap
|
||||
# Silo Gap Analysis
|
||||
|
||||
**Date:** 2026-02-08
|
||||
**Date:** 2026-02-13
|
||||
**Status:** Analysis Complete (Updated)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document analyzes the current state of the Silo project against its specification, identifies documentation and feature gaps, and outlines a roadmap for enhanced revision control capabilities.
|
||||
This document analyzes the current state of the Silo project against its specification and against SOLIDWORKS PDM (the industry-leading product data management solution). It identifies documentation gaps, feature gaps, and outlines a roadmap for enhanced revision control capabilities.
|
||||
|
||||
See [ROADMAP.md](ROADMAP.md) for the platform roadmap and dependency tier structure.
|
||||
|
||||
---
|
||||
|
||||
@@ -25,7 +27,7 @@ This document analyzes the current state of the Silo project against its specifi
|
||||
| `docs/AUTH.md` | Authentication system design | Current |
|
||||
| `docs/AUTH_USER_GUIDE.md` | User guide for login, tokens, and roles | Current |
|
||||
| `docs/GAP_ANALYSIS.md` | Revision control roadmap | Current |
|
||||
| `ROADMAP.md` | Feature roadmap and SOLIDWORKS PDM comparison | Current |
|
||||
| `docs/ROADMAP.md` | Platform roadmap and dependency tiers | Current |
|
||||
| `frontend-spec.md` | React SPA frontend specification | Current |
|
||||
|
||||
### 1.2 Documentation Gaps (Priority Order)
|
||||
@@ -74,7 +76,7 @@ This document analyzes the current state of the Silo project against its specifi
|
||||
| Append-only revision history | Complete | `internal/db/items.go` |
|
||||
| Sequential revision numbering | Complete | Database trigger |
|
||||
| Property snapshots (JSONB) | Complete | `revisions.properties` |
|
||||
| File versioning (MinIO) | Complete | `internal/storage/` |
|
||||
| File storage (filesystem) | Complete | `internal/storage/` |
|
||||
| SHA256 checksums | Complete | Captured on upload |
|
||||
| Revision comments | Complete | `revisions.comment` |
|
||||
| User attribution | Complete | `revisions.created_by` |
|
||||
@@ -91,7 +93,7 @@ CREATE TABLE revisions (
|
||||
revision_number INTEGER NOT NULL,
|
||||
properties JSONB NOT NULL DEFAULT '{}',
|
||||
file_key TEXT,
|
||||
file_version TEXT, -- MinIO version ID
|
||||
file_version TEXT, -- storage version ID
|
||||
file_checksum TEXT, -- SHA256
|
||||
file_size BIGINT,
|
||||
thumbnail_key TEXT,
|
||||
@@ -281,7 +283,7 @@ Effort: Medium | Priority: Low | Risk: Low
|
||||
|
||||
**Changes:**
|
||||
- Add thumbnail generation on file upload
|
||||
- Store in MinIO at `thumbnails/{part_number}/rev{n}.png`
|
||||
- Store at `thumbnails/{part_number}/rev{n}.png`
|
||||
- Expose via `GET /api/items/{pn}/thumbnail/{rev}`
|
||||
|
||||
---
|
||||
@@ -375,7 +377,7 @@ internal/
|
||||
relationships.go # BOM repository
|
||||
projects.go # Project repository
|
||||
storage/
|
||||
storage.go # MinIO file storage helpers
|
||||
storage.go # File storage helpers
|
||||
migrations/
|
||||
001_initial.sql # Core schema
|
||||
...
|
||||
@@ -450,3 +452,163 @@ GET /api/releases/{name} # Get release details
|
||||
POST /api/releases/{name}/items # Add items to release
|
||||
GET /api/items/{pn}/thumbnail/{rev} # Get thumbnail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix C: SOLIDWORKS PDM Comparison
|
||||
|
||||
This section compares Silo's capabilities against SOLIDWORKS PDM features. Gaps are categorized by priority and implementation complexity.
|
||||
|
||||
**Legend:** Silo Status = Full / Partial / None | Priority = Critical / High / Medium / Low | Complexity = Simple / Moderate / Complex
|
||||
|
||||
### C.1 Version Control & Revision Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Check-in/check-out | Full pessimistic locking | None | High | Moderate |
|
||||
| Version history | Complete with branching | Full (linear) | - | - |
|
||||
| Revision labels | A, B, C or custom schemes | Full (custom labels) | - | - |
|
||||
| Rollback/restore | Full | Full | - | - |
|
||||
| Compare revisions | Visual + metadata diff | Metadata diff only | Medium | Complex |
|
||||
| Get Latest Revision | One-click retrieval | Partial (API only) | Medium | Simple |
|
||||
|
||||
Silo lacks pessimistic locking (check-out), which is critical for multi-user CAD environments where file merging is impractical. Visual diff comparison would require FreeCAD integration for CAD file visualization.
|
||||
|
||||
### C.2 Workflow Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Custom workflows | Full visual designer | None | Critical | Complex |
|
||||
| State transitions | Configurable with permissions | Basic (status field only) | Critical | Complex |
|
||||
| Parallel approvals | Multiple approvers required | None | High | Complex |
|
||||
| Automatic transitions | Timer/condition-based | None | Medium | Moderate |
|
||||
| Email notifications | On state change | None | High | Moderate |
|
||||
| ECO process | Built-in change management | None | High | Complex |
|
||||
| Child state conditions | Block parent if children invalid | None | Medium | Moderate |
|
||||
|
||||
Workflow management is the largest functional gap. SOLIDWORKS PDM offers sophisticated state machines with parallel approvals, automatic transitions, and deep integration with engineering change processes. Silo currently has only a simple status field (draft/review/released/obsolete) with no transition rules or approval processes.
|
||||
|
||||
### C.3 User Management & Security
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| User authentication | Windows AD, LDAP | Full (local, LDAP, OIDC) | - | - |
|
||||
| Role-based permissions | Granular per folder/state | Partial (3-tier role model) | Medium | Moderate |
|
||||
| Group management | Full | None | Medium | Moderate |
|
||||
| Folder permissions | Read/write/delete per folder | None | Medium | Moderate |
|
||||
| State permissions | Actions allowed per state | None | High | Moderate |
|
||||
| Audit trail | Complete action logging | Full | - | - |
|
||||
| Private files | Pre-check-in visibility control | None | Low | Simple |
|
||||
|
||||
Authentication is implemented with three backends (local, LDAP/FreeIPA, OIDC/Keycloak) and a 3-tier role model (admin > editor > viewer). Audit logging captures user actions. Remaining gaps: group management, folder-level permissions, and state-based permission rules.
|
||||
|
||||
### C.4 Search & Discovery
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Metadata search | Full with custom cards | Partial (API query params + fuzzy) | High | Moderate |
|
||||
| Full-text content search | iFilters for Office, CAD | None | Medium | Complex |
|
||||
| Quick search | Toolbar with history | Partial (fuzzy search API) | Medium | Simple |
|
||||
| Saved searches | User-defined favorites | None | Medium | Simple |
|
||||
| Advanced operators | AND, OR, NOT, wildcards | None | Medium | Simple |
|
||||
| Multi-variable search | Search across multiple fields | None | Medium | Simple |
|
||||
| Where-used search | Find all assemblies using part | Full | - | - |
|
||||
|
||||
Silo has API-level filtering, fuzzy search, and where-used queries. Remaining gaps: saved searches, advanced search operators, and a richer search UI. Content search (searching within CAD files) is not planned for the server.
|
||||
|
||||
### C.5 BOM Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Single-level BOM | Yes | Full | - | - |
|
||||
| Multi-level BOM | Indented/exploded views | Full (recursive, configurable depth) | - | - |
|
||||
| BOM comparison | Between revisions | None | Medium | Moderate |
|
||||
| BOM export | Excel, XML, ERP formats | Full (CSV, ODS) | - | - |
|
||||
| BOM import | Bulk BOM loading | Full (CSV with upsert) | - | - |
|
||||
| Calculated BOMs | Quantities rolled up | None | Medium | Moderate |
|
||||
| Reference designators | Full support | Full | - | - |
|
||||
| Alternate parts | Substitute tracking | Full | - | - |
|
||||
|
||||
Multi-level BOM retrieval (recursive CTE with configurable depth) and BOM export (CSV, ODS) are implemented. BOM import supports CSV with upsert and cycle detection. Remaining gap: BOM comparison between revisions.
|
||||
|
||||
### C.6 CAD Integration
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Native CAD add-in | Deep SOLIDWORKS integration | FreeCAD workbench (silo-mod) | Medium | Complex |
|
||||
| Property mapping | Bi-directional sync | Planned (silo-mod) | Medium | Moderate |
|
||||
| Task pane | Embedded in CAD UI | Auth dock panel (silo-mod) | Medium | Complex |
|
||||
| Lightweight components | Handle without full load | N/A | - | - |
|
||||
| Drawing/model linking | Automatic association | Manual | Medium | Moderate |
|
||||
| Multi-CAD support | Third-party formats | FreeCAD only | Low | - |
|
||||
|
||||
CAD integration is maintained in separate repositories ([silo-mod](https://git.kindred-systems.com/kindred/silo-mod), [silo-calc](https://git.kindred-systems.com/kindred/silo-calc)). The Silo server provides the REST API endpoints consumed by those clients.
|
||||
|
||||
### C.7 External Integrations
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| ERP integration | SAP, Dynamics, etc. | Partial (Odoo stubs) | Medium | Complex |
|
||||
| API access | Full COM/REST API | Full REST API (78 endpoints) | - | - |
|
||||
| Dispatch scripts | Automation without coding | None | Medium | Moderate |
|
||||
| Task scheduler | Background processing | None | Medium | Moderate |
|
||||
| Email system | SMTP integration | None | High | Simple |
|
||||
| Web portal | Browser access | Full (React SPA + auth) | - | - |
|
||||
|
||||
Silo has a comprehensive REST API (78 endpoints) and a full web UI with authentication. Odoo ERP integration has config/sync-log scaffolding but push/pull operations are stubs. Remaining gaps: email notifications, task scheduler, dispatch automation.
|
||||
|
||||
### C.8 Reporting & Analytics
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Standard reports | Inventory, usage, activity | None | Medium | Moderate |
|
||||
| Custom reports | User-defined queries | None | Medium | Moderate |
|
||||
| Dashboard | Visual KPIs | None | Low | Moderate |
|
||||
| Export formats | PDF, Excel, CSV | CSV and ODS | Medium | Simple |
|
||||
|
||||
Reporting capabilities are absent. Basic reports (item counts, revision activity, where-used) would provide immediate value.
|
||||
|
||||
### C.9 File Handling
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| File versioning | Automatic | Full (filesystem) | - | - |
|
||||
| File preview | Thumbnails, 3D preview | None | Medium | Complex |
|
||||
| File conversion | PDF, DXF generation | None | Medium | Complex |
|
||||
| Replication | Multi-site sync | None | Low | Complex |
|
||||
| File copy with refs | Copy tree with references | None | Medium | Moderate |
|
||||
|
||||
File storage works well. Thumbnail generation and file preview would significantly improve the web UI experience. Automatic conversion to PDF/DXF is valuable for sharing with non-CAD users.
|
||||
|
||||
---
|
||||
|
||||
## Appendix D: Feature Comparison Matrix
|
||||
|
||||
| Category | Feature | SW PDM Standard | SW PDM Pro | Silo Current | Silo Planned |
|
||||
|----------|---------|-----------------|------------|--------------|--------------|
|
||||
| **Version Control** | Check-in/out | Yes | Yes | No | Tier 1 |
|
||||
| | Version history | Yes | Yes | Yes | - |
|
||||
| | Rollback | Yes | Yes | Yes | - |
|
||||
| | Revision labels/status | Yes | Yes | Yes | - |
|
||||
| | Revision comparison | Yes | Yes | Yes (metadata) | - |
|
||||
| **Workflow** | Custom workflows | Limited | Yes | No | Tier 4 |
|
||||
| | Parallel approval | No | Yes | No | Tier 4 |
|
||||
| | Notifications | No | Yes | No | Tier 1 |
|
||||
| **Security** | User auth | Windows | Windows/LDAP | Yes (local, LDAP, OIDC) | - |
|
||||
| | Permissions | Basic | Granular | Partial (role-based) | Tier 4 |
|
||||
| | Audit trail | Basic | Full | Yes | - |
|
||||
| **Search** | Metadata search | Yes | Yes | Partial (API + fuzzy) | Tier 0 |
|
||||
| | Content search | No | Yes | No | Tier 2 |
|
||||
| | Where-used | Yes | Yes | Yes | - |
|
||||
| **BOM** | Single-level | Yes | Yes | Yes | - |
|
||||
| | Multi-level | Yes | Yes | Yes (recursive) | - |
|
||||
| | BOM export | Yes | Yes | Yes (CSV, ODS) | - |
|
||||
| **Data** | CSV import/export | Yes | Yes | Yes | - |
|
||||
| | ODS import/export | No | No | Yes | - |
|
||||
| | Project management | Yes | Yes | Yes | - |
|
||||
| **Integration** | API | Limited | Full | Full REST (78) | - |
|
||||
| | ERP connectors | No | Yes | Partial (Odoo stubs) | Tier 6 |
|
||||
| | Web access | No | Yes | Yes (React SPA + auth) | - |
|
||||
| **Files** | Versioning | Yes | Yes | Yes | - |
|
||||
| | Preview | Yes | Yes | No | Tier 2 |
|
||||
| | Multi-site | No | Yes | No | Not Planned |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
This guide covers two installation methods:
|
||||
|
||||
- **[Option A: Docker Compose](#option-a-docker-compose)** — self-contained stack with all services. Recommended for evaluation, small teams, and environments where Docker is the standard.
|
||||
- **[Option B: Daemon Install](#option-b-daemon-install-systemd--external-services)** — systemd service with external PostgreSQL, MinIO, and optional LDAP/nginx. Recommended for production deployments integrated with existing infrastructure.
|
||||
- **[Option B: Daemon Install](#option-b-daemon-install-systemd--external-services)** — systemd service with external PostgreSQL and optional LDAP/nginx. Files are stored on the local filesystem. Recommended for production deployments integrated with existing infrastructure.
|
||||
|
||||
Both methods produce the same result: a running Silo server with a web UI, REST API, and authentication.
|
||||
|
||||
@@ -48,7 +48,7 @@ Regardless of which method you choose:
|
||||
|
||||
## Option A: Docker Compose
|
||||
|
||||
A single Docker Compose file runs everything: PostgreSQL, MinIO, OpenLDAP, and Silo. An optional nginx container can be enabled for reverse proxying.
|
||||
A single Docker Compose file runs everything: PostgreSQL, OpenLDAP, and Silo. Files are stored on the local filesystem. An optional nginx container can be enabled for reverse proxying.
|
||||
|
||||
### A.1 Prerequisites
|
||||
|
||||
@@ -80,7 +80,6 @@ The setup script generates credentials and configuration files:
|
||||
It prompts for:
|
||||
- Server domain (default: `localhost`)
|
||||
- PostgreSQL password (auto-generated if you press Enter)
|
||||
- MinIO credentials (auto-generated)
|
||||
- OpenLDAP admin password and initial user (auto-generated)
|
||||
- Silo local admin account (fallback when LDAP is unavailable)
|
||||
|
||||
@@ -106,7 +105,7 @@ Wait for all services to become healthy:
|
||||
docker compose -f deployments/docker-compose.allinone.yaml ps
|
||||
```
|
||||
|
||||
You should see `silo-postgres`, `silo-minio`, `silo-openldap`, and `silo-api` all in a healthy state.
|
||||
You should see `silo-postgres`, `silo-openldap`, and `silo-api` all in a healthy state.
|
||||
|
||||
View logs:
|
||||
|
||||
@@ -124,7 +123,7 @@ docker compose -f deployments/docker-compose.allinone.yaml logs -f silo
|
||||
# Health check
|
||||
curl http://localhost:8080/health
|
||||
|
||||
# Readiness check (includes database and storage connectivity)
|
||||
# Readiness check (includes database connectivity)
|
||||
curl http://localhost:8080/ready
|
||||
```
|
||||
|
||||
@@ -226,7 +225,7 @@ The Silo container is rebuilt from the updated source. Database migrations in `m
|
||||
|
||||
## Option B: Daemon Install (systemd + External Services)
|
||||
|
||||
This method runs Silo as a systemd service on a dedicated host, connecting to externally managed PostgreSQL, MinIO, and optionally LDAP services.
|
||||
This method runs Silo as a systemd service on a dedicated host, connecting to externally managed PostgreSQL and optionally LDAP services. Files are stored on the local filesystem.
|
||||
|
||||
### B.1 Architecture Overview
|
||||
|
||||
@@ -240,21 +239,22 @@ This method runs Silo as a systemd service on a dedicated host, connecting to ex
|
||||
│ ┌───────▼────────┐ │
|
||||
│ │ silod │ │
|
||||
│ │ (API server) │ │
|
||||
│ └──┬─────────┬───┘ │
|
||||
└─────┼─────────┼──────┘
|
||||
│ │
|
||||
┌───────────▼──┐ ┌───▼──────────────┐
|
||||
│ PostgreSQL 16│ │ MinIO (S3) │
|
||||
│ :5432 │ │ :9000 API │
|
||||
└──────────────┘ │ :9001 Console │
|
||||
└──────────────────┘
|
||||
│ │ Files: /opt/ │ │
|
||||
│ │ silo/data │ │
|
||||
│ └──────┬─────────┘ │
|
||||
└─────────┼────────────┘
|
||||
│
|
||||
┌───────────▼──┐
|
||||
│ PostgreSQL 16│
|
||||
│ :5432 │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### B.2 Prerequisites
|
||||
|
||||
- Linux host (Debian/Ubuntu or RHEL/Fedora/AlmaLinux)
|
||||
- Root or sudo access
|
||||
- Network access to your PostgreSQL and MinIO servers
|
||||
- Network access to your PostgreSQL server
|
||||
|
||||
The setup script installs Go and other build dependencies automatically.
|
||||
|
||||
@@ -281,26 +281,6 @@ Verify:
|
||||
psql -h YOUR_PG_HOST -U silo -d silo -c 'SELECT 1'
|
||||
```
|
||||
|
||||
#### MinIO
|
||||
|
||||
Install MinIO and create a bucket and service account:
|
||||
|
||||
- [MinIO quickstart](https://min.io/docs/minio/linux/index.html)
|
||||
|
||||
```bash
|
||||
# Using the MinIO client (mc):
|
||||
mc alias set local http://YOUR_MINIO_HOST:9000 minioadmin minioadmin
|
||||
mc mb local/silo-files
|
||||
mc admin user add local silouser YOUR_MINIO_SECRET
|
||||
mc admin policy attach local readwrite --user silouser
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
curl -I http://YOUR_MINIO_HOST:9000/minio/health/live
|
||||
```
|
||||
|
||||
#### LDAP / FreeIPA (Optional)
|
||||
|
||||
For LDAP authentication, you need an LDAP server with user and group entries. Options:
|
||||
@@ -339,10 +319,10 @@ The script:
|
||||
4. Clones the repository
|
||||
5. Creates the environment file template
|
||||
|
||||
To override the default service hostnames:
|
||||
To override the default database hostname:
|
||||
|
||||
```bash
|
||||
SILO_DB_HOST=db.example.com SILO_MINIO_HOST=s3.example.com sudo -E bash scripts/setup-host.sh
|
||||
SILO_DB_HOST=db.example.com sudo -E bash scripts/setup-host.sh
|
||||
```
|
||||
|
||||
### B.5 Configure Credentials
|
||||
@@ -357,10 +337,6 @@ sudo nano /etc/silo/silod.env
|
||||
# Database
|
||||
SILO_DB_PASSWORD=your-database-password
|
||||
|
||||
# MinIO
|
||||
SILO_MINIO_ACCESS_KEY=silouser
|
||||
SILO_MINIO_SECRET_KEY=your-minio-secret
|
||||
|
||||
# Authentication
|
||||
SILO_SESSION_SECRET=generate-a-long-random-string
|
||||
SILO_ADMIN_USERNAME=admin
|
||||
@@ -379,7 +355,7 @@ Review the server configuration:
|
||||
sudo nano /etc/silo/config.yaml
|
||||
```
|
||||
|
||||
Update `database.host`, `storage.endpoint`, `server.base_url`, and authentication settings for your environment. See [CONFIGURATION.md](CONFIGURATION.md) for all options.
|
||||
Update `database.host`, `storage.filesystem.root_dir`, `server.base_url`, and authentication settings for your environment. See [CONFIGURATION.md](CONFIGURATION.md) for all options.
|
||||
|
||||
### B.6 Deploy
|
||||
|
||||
@@ -412,10 +388,10 @@ sudo /opt/silo/src/scripts/deploy.sh --restart-only
|
||||
sudo /opt/silo/src/scripts/deploy.sh --status
|
||||
```
|
||||
|
||||
To override the target host or database host:
|
||||
To override the target host:
|
||||
|
||||
```bash
|
||||
SILO_DEPLOY_TARGET=silo.example.com SILO_DB_HOST=db.example.com sudo -E scripts/deploy.sh
|
||||
SILO_DEPLOY_TARGET=silo.example.com sudo -E scripts/deploy.sh
|
||||
```
|
||||
|
||||
### B.7 Set Up Nginx and TLS
|
||||
|
||||
485
docs/src/silo-server/KC_SERVER.md
Normal file
@@ -0,0 +1,485 @@
|
||||
# .kc Server-Side Metadata Integration
|
||||
|
||||
**Status:** Draft
|
||||
**Date:** February 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
When a `.kc` file is committed to Silo, the server extracts and indexes the `silo/` directory contents so that metadata is queryable, diffable, and streamable without downloading the full file. This document specifies the server-side processing pipeline, database storage, API endpoints, and SSE events that support the Create viewport widgets defined in [SILO_VIEWPORT.md](SILO_VIEWPORT.md).
|
||||
|
||||
The core principle: **the `.kc` file is the transport format; Silo is the index.** The `silo/` directory entries are extracted into database columns on commit and packed back into the ZIP on checkout. The server never modifies the FreeCAD standard zone (`Document.xml`, `.brp` files, `thumbnails/`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Commit Pipeline
|
||||
|
||||
When a `.kc` file is uploaded via `POST /api/items/{partNumber}/file`, the server runs an extraction pipeline before returning success.
|
||||
|
||||
### 2.1 Pipeline Steps
|
||||
|
||||
```
|
||||
Client uploads .kc file
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 1. Store file to disk | (existing behavior -- unchanged)
|
||||
| items/{pn}/rev{N}.kc |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 2. Open ZIP, read silo/ |
|
||||
| Parse each entry |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 3. Validate manifest.json |
|
||||
| - UUID matches item |
|
||||
| - kc_version supported |
|
||||
| - revision_hash present |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 4. Index metadata |
|
||||
| - Upsert item_metadata |
|
||||
| - Upsert dependencies |
|
||||
| - Append history entry |
|
||||
| - Snapshot approvals |
|
||||
| - Register macros |
|
||||
| - Register job defs |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 5. Broadcast SSE events |
|
||||
| - revision.created |
|
||||
| - metadata.updated |
|
||||
| - bom.changed (if deps |
|
||||
| differ from previous) |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
Return 201 Created
|
||||
```
|
||||
|
||||
### 2.2 Validation Rules
|
||||
|
||||
| Check | Failure response |
|
||||
|-------|-----------------|
|
||||
| `silo/manifest.json` missing | `400 Bad Request` -- file is `.fcstd` not `.kc` |
|
||||
| `manifest.uuid` doesn't match item's UUID | `409 Conflict` -- wrong item |
|
||||
| `manifest.kc_version` > server's supported version | `422 Unprocessable` -- client newer than server |
|
||||
| `manifest.revision_hash` matches current head | `200 OK` (no-op, file unchanged) |
|
||||
| Any `silo/` JSON fails to parse | `422 Unprocessable` with path and parse error |
|
||||
|
||||
If validation fails, the blob is still stored (the user uploaded it), but no metadata indexing occurs. The item's revision is created with a `metadata_error` flag so the web UI can surface the problem.
|
||||
|
||||
### 2.3 Backward Compatibility
|
||||
|
||||
Plain `.fcstd` files (no `silo/` directory) continue to work exactly as today -- stored on disk, revision created, no metadata extraction. The pipeline short-circuits at step 2 when no `silo/` directory is found.
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Schema
|
||||
|
||||
### 3.1 `item_metadata` Table
|
||||
|
||||
Stores the indexed contents of `silo/metadata.json` as structured JSONB, searchable and filterable via the existing item query endpoints.
|
||||
|
||||
```sql
|
||||
CREATE TABLE item_metadata (
|
||||
item_id UUID PRIMARY KEY REFERENCES items(id) ON DELETE CASCADE,
|
||||
schema_name TEXT,
|
||||
tags TEXT[] NOT NULL DEFAULT '{}',
|
||||
lifecycle_state TEXT NOT NULL DEFAULT 'draft',
|
||||
fields JSONB NOT NULL DEFAULT '{}',
|
||||
kc_version TEXT,
|
||||
manifest_uuid UUID,
|
||||
silo_instance TEXT,
|
||||
revision_hash TEXT,
|
||||
updated_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_by TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX idx_item_metadata_tags ON item_metadata USING GIN (tags);
|
||||
CREATE INDEX idx_item_metadata_lifecycle ON item_metadata (lifecycle_state);
|
||||
CREATE INDEX idx_item_metadata_fields ON item_metadata USING GIN (fields);
|
||||
```
|
||||
|
||||
On commit, the server upserts this row from `silo/manifest.json` and `silo/metadata.json`. The `fields` column contains the schema-driven key-value pairs exactly as they appear in the JSON.
|
||||
|
||||
### 3.2 `item_dependencies` Table
|
||||
|
||||
Stores the indexed contents of `silo/dependencies.json`. Replaces the BOM for assembly relationships that originate from the CAD model.
|
||||
|
||||
```sql
|
||||
CREATE TABLE item_dependencies (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
parent_item_id UUID REFERENCES items(id) ON DELETE CASCADE,
|
||||
child_uuid UUID NOT NULL,
|
||||
child_part_number TEXT,
|
||||
child_revision INTEGER,
|
||||
quantity DECIMAL,
|
||||
label TEXT,
|
||||
relationship TEXT NOT NULL DEFAULT 'component',
|
||||
revision_number INTEGER NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_item_deps_parent ON item_dependencies (parent_item_id);
|
||||
CREATE INDEX idx_item_deps_child ON item_dependencies (child_uuid);
|
||||
```
|
||||
|
||||
This table complements the existing `relationships` table. The `relationships` table is the server-authoritative BOM (editable via the web UI and API). The `item_dependencies` table is the CAD-authoritative record extracted from the file. BOM merge (per [BOM_MERGE.md](BOM_MERGE.md)) reconciles the two.
|
||||
|
||||
### 3.3 `item_approvals` Table
|
||||
|
||||
Stores the indexed contents of `silo/approvals.json`. Server-authoritative -- the `.kc` snapshot is a read cache.
|
||||
|
||||
```sql
|
||||
CREATE TABLE item_approvals (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
item_id UUID REFERENCES items(id) ON DELETE CASCADE,
|
||||
eco_number TEXT,
|
||||
state TEXT NOT NULL DEFAULT 'draft',
|
||||
updated_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_by TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE approval_signatures (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
approval_id UUID REFERENCES item_approvals(id) ON DELETE CASCADE,
|
||||
username TEXT NOT NULL,
|
||||
role TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
signed_at TIMESTAMPTZ,
|
||||
comment TEXT
|
||||
);
|
||||
```
|
||||
|
||||
These tables exist independent of `.kc` commits -- approvals are created and managed through the web UI and API. On `.kc` checkout, the current approval state is serialized into `silo/approvals.json` for offline display.
|
||||
|
||||
### 3.4 `item_macros` Table
|
||||
|
||||
Registers macros from `silo/macros/` for server-side discoverability and the future Macro Store module.
|
||||
|
||||
```sql
|
||||
CREATE TABLE item_macros (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
item_id UUID REFERENCES items(id) ON DELETE CASCADE,
|
||||
filename TEXT NOT NULL,
|
||||
trigger TEXT NOT NULL DEFAULT 'manual',
|
||||
content TEXT NOT NULL,
|
||||
revision_number INTEGER NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
UNIQUE(item_id, filename)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpoints
|
||||
|
||||
These endpoints serve the viewport widgets in Create. All are under `/api/items/{partNumber}` and follow the existing auth model.
|
||||
|
||||
### 4.1 Metadata
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/metadata` | viewer | Get indexed metadata (schema fields, tags, lifecycle) |
|
||||
| `PUT` | `/metadata` | editor | Update metadata fields from client |
|
||||
| `PATCH` | `/metadata/lifecycle` | editor | Transition lifecycle state |
|
||||
| `PATCH` | `/metadata/tags` | editor | Add/remove tags |
|
||||
|
||||
**`GET /api/items/{partNumber}/metadata`**
|
||||
|
||||
Returns the indexed metadata for viewport display. This is the fast path -- reads from `item_metadata` rather than downloading and parsing the `.kc` ZIP.
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_name": "mechanical-part-v2",
|
||||
"lifecycle_state": "draft",
|
||||
"tags": ["structural", "aluminum"],
|
||||
"fields": {
|
||||
"material": "6061-T6",
|
||||
"finish": "anodized",
|
||||
"weight_kg": 0.34,
|
||||
"category": "bracket"
|
||||
},
|
||||
"manifest": {
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"silo_instance": "https://silo.example.com",
|
||||
"revision_hash": "a1b2c3d4e5f6",
|
||||
"kc_version": "1.0"
|
||||
},
|
||||
"updated_at": "2026-02-13T20:30:00Z",
|
||||
"updated_by": "joseph"
|
||||
}
|
||||
```
|
||||
|
||||
**`PUT /api/items/{partNumber}/metadata`**
|
||||
|
||||
Accepts a partial update of schema fields. The server merges into the existing `fields` JSONB. This is the write-back path for the Metadata Editor widget.
|
||||
|
||||
```json
|
||||
{
|
||||
"fields": {
|
||||
"material": "7075-T6",
|
||||
"weight_kg": 0.31
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The server validates field names against the schema descriptor. Unknown fields are rejected with `422`.
|
||||
|
||||
**`PATCH /api/items/{partNumber}/metadata/lifecycle`**
|
||||
|
||||
Transitions lifecycle state. The server validates the transition is permitted (e.g., `draft` -> `review` is allowed, `released` -> `draft` is not without admin override).
|
||||
|
||||
```json
|
||||
{ "state": "review" }
|
||||
```
|
||||
|
||||
### 4.2 Dependencies
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/dependencies` | viewer | Get CAD-extracted dependency list |
|
||||
| `GET` | `/dependencies/resolve` | viewer | Resolve UUIDs to current part numbers and file status |
|
||||
|
||||
**`GET /api/items/{partNumber}/dependencies`**
|
||||
|
||||
Returns the raw dependency list from the last `.kc` commit.
|
||||
|
||||
**`GET /api/items/{partNumber}/dependencies/resolve`**
|
||||
|
||||
Returns the dependency list with each UUID resolved to its current part number, revision, and whether the file exists on disk. This is what the Dependency Table widget calls to populate the status column.
|
||||
|
||||
```json
|
||||
{
|
||||
"links": [
|
||||
{
|
||||
"uuid": "660e8400-...",
|
||||
"part_number": "KC-BRK-0042",
|
||||
"label": "Base Plate",
|
||||
"revision": 2,
|
||||
"quantity": 1,
|
||||
"resolved": true,
|
||||
"file_available": true
|
||||
},
|
||||
{
|
||||
"uuid": "770e8400-...",
|
||||
"part_number": "KC-HDW-0108",
|
||||
"label": "M6 SHCS",
|
||||
"revision": 1,
|
||||
"quantity": 4,
|
||||
"resolved": true,
|
||||
"file_available": true
|
||||
},
|
||||
{
|
||||
"uuid": "880e8400-...",
|
||||
"part_number": null,
|
||||
"label": "Cover Panel",
|
||||
"revision": 1,
|
||||
"quantity": 1,
|
||||
"resolved": false,
|
||||
"file_available": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Approvals
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/approvals` | viewer | Get current approval state |
|
||||
| `POST` | `/approvals` | editor | Create ECO / start approval workflow |
|
||||
| `POST` | `/approvals/{id}/sign` | editor | Sign (approve/reject) |
|
||||
|
||||
These endpoints power the Approvals Viewer widget. The viewer is read-only in Create -- sign actions happen in the web UI, but the API exists for both.
|
||||
|
||||
### 4.4 Macros
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/macros` | viewer | List registered macros |
|
||||
| `GET` | `/macros/{filename}` | viewer | Get macro source |
|
||||
|
||||
Read-only server-side. Macros are authored in Create and committed inside the `.kc`. The server indexes them for discoverability in the future Macro Store.
|
||||
|
||||
### 4.5 Existing Endpoints (unchanged)
|
||||
|
||||
The viewport widgets also consume these existing endpoints:
|
||||
|
||||
| Widget | Endpoint | Purpose |
|
||||
|--------|----------|---------|
|
||||
| History Viewer | `GET /api/items/{pn}/revisions` | Full revision list |
|
||||
| History Viewer | `GET /api/items/{pn}/revisions/compare` | Property diff |
|
||||
| Job Viewer | `GET /api/jobs?item={pn}&definition={name}&limit=1` | Last job run |
|
||||
| Job Viewer | `POST /api/jobs` | Trigger job |
|
||||
| Job Viewer | `GET /api/jobs/{id}/logs` | Job log |
|
||||
| Manifest Viewer | `GET /api/items/{pn}` | Item details (UUID, etc.) |
|
||||
|
||||
No changes needed to these -- they already exist and return the data the widgets need.
|
||||
|
||||
---
|
||||
|
||||
## 5. Checkout Pipeline
|
||||
|
||||
When a client downloads a `.kc` via `GET /api/items/{partNumber}/file`, the server packs current server-side state into the `silo/` directory before serving the file. This ensures the client always gets the latest metadata, even if it was edited via the web UI since the last commit.
|
||||
|
||||
### 5.1 Pipeline Steps
|
||||
|
||||
```
|
||||
Client requests file download
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 1. Read .kc from disk |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 2. Pack silo/ from DB |
|
||||
| - manifest.json (item) |
|
||||
| - metadata.json (index) |
|
||||
| - history.json (revs) |
|
||||
| - approvals.json (ECO) |
|
||||
| - dependencies.json |
|
||||
| - macros/ (index) |
|
||||
| - jobs/ (job defs) |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------+
|
||||
| 3. Replace silo/ in ZIP |
|
||||
| Remove old entries |
|
||||
| Write packed entries |
|
||||
+-----------------------------+
|
||||
|
|
||||
v
|
||||
Stream .kc to client
|
||||
```
|
||||
|
||||
### 5.2 Packing Rules
|
||||
|
||||
| `silo/` entry | Source | Notes |
|
||||
|---------------|--------|-------|
|
||||
| `manifest.json` | `item_metadata` + `items` table | UUID from item, revision_hash from latest revision |
|
||||
| `metadata.json` | `item_metadata.fields` + tags + lifecycle | Serialized from indexed columns |
|
||||
| `history.json` | `revisions` table | Last 20 revisions for this item |
|
||||
| `approvals.json` | `item_approvals` + `approval_signatures` | Current ECO state, omitted if no active ECO |
|
||||
| `dependencies.json` | `item_dependencies` | Current revision's dependency list |
|
||||
| `macros/*.py` | `item_macros` | All registered macros |
|
||||
| `jobs/*.yaml` | `job_definitions` filtered by item type | Job definitions matching this item's trigger filters |
|
||||
|
||||
### 5.3 Caching
|
||||
|
||||
Packing the `silo/` directory on every download has a cost. To mitigate:
|
||||
|
||||
- **ETag header**: The response includes an ETag computed from the revision number + metadata `updated_at`. If the client sends `If-None-Match`, the server can return `304 Not Modified`.
|
||||
- **Lazy packing**: If the `.kc` blob's `silo/manifest.json` revision_hash matches the current head *and* `item_metadata.updated_at` is older than the blob's upload time, skip repacking entirely -- the blob is already current.
|
||||
|
||||
---
|
||||
|
||||
## 6. SSE Events
|
||||
|
||||
The viewport widgets subscribe to SSE for live updates. These events are broadcast when server-side metadata changes, whether via `.kc` commit, web UI edit, or API call.
|
||||
|
||||
| Event | Payload | Trigger |
|
||||
|-------|---------|---------|
|
||||
| `metadata.updated` | `{part_number, changed_fields[], lifecycle_state, updated_by}` | Metadata PUT/PATCH |
|
||||
| `metadata.lifecycle` | `{part_number, from_state, to_state, updated_by}` | Lifecycle transition |
|
||||
| `metadata.tags` | `{part_number, added[], removed[]}` | Tag add/remove |
|
||||
| `approval.created` | `{part_number, eco_number, state}` | ECO created |
|
||||
| `approval.signed` | `{part_number, eco_number, user, role, status}` | Approver action |
|
||||
| `approval.completed` | `{part_number, eco_number, final_state}` | All approvers acted |
|
||||
| `dependencies.changed` | `{part_number, added[], removed[], changed[]}` | Dependency diff on commit |
|
||||
|
||||
Existing events (`revision.created`, `job.*`, `bom.changed`) continue to work as documented in [SPECIFICATION.md](SPECIFICATION.md) and [WORKERS.md](WORKERS.md).
|
||||
|
||||
### 6.1 Widget Subscription Map
|
||||
|
||||
| Viewport widget | Subscribes to |
|
||||
|-----------------|---------------|
|
||||
| Manifest Viewer | -- (read-only, no live updates) |
|
||||
| Metadata Editor | `metadata.updated`, `metadata.lifecycle`, `metadata.tags` |
|
||||
| History Viewer | `revision.created` |
|
||||
| Approvals Viewer | `approval.created`, `approval.signed`, `approval.completed` |
|
||||
| Dependency Table | `dependencies.changed` |
|
||||
| Job Viewer | `job.created`, `job.progress`, `job.completed`, `job.failed` |
|
||||
| Macro Editor | -- (local-only until committed) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Web UI Integration
|
||||
|
||||
The Silo web UI also benefits from indexed metadata. These are additions to existing pages, not new pages.
|
||||
|
||||
### 7.1 Items Page
|
||||
|
||||
The item detail panel gains a **Metadata** tab (alongside Main, Properties, Revisions, BOM, Where Used) showing the schema-driven form from `GET /api/items/{pn}/metadata`. Editable for editors.
|
||||
|
||||
### 7.2 Items List
|
||||
|
||||
New filterable columns: `lifecycle_state`, `tags`. The existing search endpoint gains metadata-aware filtering:
|
||||
|
||||
```
|
||||
GET /api/items?lifecycle=released&tag=aluminum
|
||||
GET /api/items/search?q=bracket&lifecycle=draft
|
||||
```
|
||||
|
||||
### 7.3 Approvals Page
|
||||
|
||||
A new page accessible from the top navigation (visible when a future `approvals` module is enabled). Lists all active ECOs with their approval progress.
|
||||
|
||||
---
|
||||
|
||||
## 8. Migration
|
||||
|
||||
### 8.1 Database Migration
|
||||
|
||||
A single migration adds the `item_metadata`, `item_dependencies`, `item_approvals`, `approval_signatures`, and `item_macros` tables. Existing items have no metadata rows -- they're created on first `.kc` commit or via `PUT /api/items/{pn}/metadata`.
|
||||
|
||||
### 8.2 Backfill
|
||||
|
||||
For items that already have `.kc` files stored on disk (committed before this feature), an admin endpoint re-runs the extraction pipeline:
|
||||
|
||||
```
|
||||
POST /api/admin/reindex-metadata
|
||||
```
|
||||
|
||||
This iterates all items with `.kc` files, opens each ZIP, and indexes the `silo/` contents. Idempotent -- safe to run multiple times.
|
||||
|
||||
---
|
||||
|
||||
## 9. Implementation Order
|
||||
|
||||
| Phase | Server work | Supports client phase |
|
||||
|-------|------------|----------------------|
|
||||
| 1 | `item_metadata` table + `GET/PUT /metadata` + commit extraction | SILO_VIEWPORT Phase 1-2 (Manifest, Metadata) |
|
||||
| 2 | Pack `silo/` on checkout + ETag caching | SILO_VIEWPORT Phase 1-3 |
|
||||
| 3 | `item_dependencies` table + `/dependencies/resolve` | SILO_VIEWPORT Phase 5 (Dependency Table) |
|
||||
| 4 | `item_macros` table + `/macros` endpoints | SILO_VIEWPORT Phase 6 (Macro Editor) |
|
||||
| 5 | `item_approvals` tables + `/approvals` endpoints | SILO_VIEWPORT Phase 7 (Approvals Viewer) |
|
||||
| 6 | SSE events for metadata/approvals/dependencies | SILO_VIEWPORT Phase 8 (Live integration) |
|
||||
| 7 | Web UI metadata tab + list filters | Independent of client |
|
||||
|
||||
Phases 1-2 are prerequisite for the viewport to work with live data. Phases 3-6 can be built in parallel with client widget development. Phase 7 is web-UI-only and independent.
|
||||
|
||||
---
|
||||
|
||||
## 10. References
|
||||
|
||||
- [SILO_VIEWPORT.md](SILO_VIEWPORT.md) -- Client-side viewport widget specification
|
||||
- [KC_SPECIFICATION.md](KC_SPECIFICATION.md) -- .kc file format specification
|
||||
- [SPECIFICATION.md](SPECIFICATION.md) -- Silo server API reference
|
||||
- [BOM_MERGE.md](BOM_MERGE.md) -- BOM merge rules (dependency reconciliation)
|
||||
- [WORKERS.md](WORKERS.md) -- Job queue (job viewer data source)
|
||||
- [MODULES.md](MODULES.md) -- Module system (approval module gating)
|
||||
- [ROADMAP.md](ROADMAP.md) -- Platform roadmap tiers
|
||||
749
docs/src/silo-server/MODULES.md
Normal file
@@ -0,0 +1,749 @@
|
||||
# Module System Specification
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-14
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Silo's module system defines the boundary between required infrastructure and optional capabilities. Each module groups a set of API endpoints, UI views, and configuration parameters. Modules can be enabled or disabled at runtime by administrators via the web UI, and clients can query which modules are active to adapt their feature set.
|
||||
|
||||
The goal: after initial deployment (where `config.yaml` sets database, storage, and server bind), all further operational configuration happens through the admin settings UI. The YAML file becomes the bootstrap; the database becomes the runtime source of truth.
|
||||
|
||||
---
|
||||
|
||||
## 2. Module Registry
|
||||
|
||||
### 2.1 Required Modules
|
||||
|
||||
These cannot be disabled. They define what Silo *is*.
|
||||
|
||||
| Module ID | Name | Description |
|
||||
|-----------|------|-------------|
|
||||
| `core` | Core PDM | Items, revisions, files, BOM, search, import/export, part number generation |
|
||||
| `schemas` | Schemas | Part numbering schema parsing, segment management, form descriptors |
|
||||
| `storage` | Storage | MinIO/S3 file storage, presigned uploads, versioning |
|
||||
|
||||
### 2.2 Optional Modules
|
||||
|
||||
| Module ID | Name | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `auth` | Authentication | `true` | Local, LDAP, OIDC authentication and RBAC |
|
||||
| `projects` | Projects | `true` | Project management and item tagging |
|
||||
| `audit` | Audit | `true` | Audit logging, completeness scoring |
|
||||
| `odoo` | Odoo ERP | `false` | Odoo integration (config, sync-log, push/pull) |
|
||||
| `freecad` | Create Integration | `true` | URI scheme, executable path, client settings |
|
||||
| `jobs` | Job Queue | `false` | Async compute jobs, runner management |
|
||||
| `dag` | Dependency DAG | `false` | Feature DAG sync, validation states, interference detection |
|
||||
|
||||
### 2.3 Module Dependencies
|
||||
|
||||
Some modules require others to function:
|
||||
|
||||
| Module | Requires |
|
||||
|--------|----------|
|
||||
| `dag` | `jobs` |
|
||||
| `jobs` | `auth` (runner tokens) |
|
||||
| `odoo` | `auth` |
|
||||
|
||||
When enabling a module, its dependencies are validated. The server rejects enabling `dag` without `jobs`. Disabling a module that others depend on shows a warning listing dependents.
|
||||
|
||||
---
|
||||
|
||||
## 3. Endpoint-to-Module Mapping
|
||||
|
||||
### 3.1 `core` (required)
|
||||
|
||||
```
|
||||
# Health
|
||||
GET /health
|
||||
GET /ready
|
||||
|
||||
# Items
|
||||
GET /api/items
|
||||
GET /api/items/search
|
||||
GET /api/items/by-uuid/{uuid}
|
||||
GET /api/items/export.csv
|
||||
GET /api/items/template.csv
|
||||
GET /api/items/export.ods
|
||||
GET /api/items/template.ods
|
||||
POST /api/items
|
||||
POST /api/items/import
|
||||
POST /api/items/import.ods
|
||||
GET /api/items/{partNumber}
|
||||
PUT /api/items/{partNumber}
|
||||
DELETE /api/items/{partNumber}
|
||||
|
||||
# Revisions
|
||||
GET /api/items/{partNumber}/revisions
|
||||
GET /api/items/{partNumber}/revisions/compare
|
||||
GET /api/items/{partNumber}/revisions/{revision}
|
||||
POST /api/items/{partNumber}/revisions
|
||||
PATCH /api/items/{partNumber}/revisions/{revision}
|
||||
POST /api/items/{partNumber}/revisions/{revision}/rollback
|
||||
|
||||
# Files
|
||||
GET /api/items/{partNumber}/files
|
||||
GET /api/items/{partNumber}/file
|
||||
GET /api/items/{partNumber}/file/{revision}
|
||||
POST /api/items/{partNumber}/file
|
||||
POST /api/items/{partNumber}/files
|
||||
DELETE /api/items/{partNumber}/files/{fileId}
|
||||
PUT /api/items/{partNumber}/thumbnail
|
||||
POST /api/uploads/presign
|
||||
|
||||
# BOM
|
||||
GET /api/items/{partNumber}/bom
|
||||
GET /api/items/{partNumber}/bom/expanded
|
||||
GET /api/items/{partNumber}/bom/flat
|
||||
GET /api/items/{partNumber}/bom/cost
|
||||
GET /api/items/{partNumber}/bom/where-used
|
||||
GET /api/items/{partNumber}/bom/export.csv
|
||||
GET /api/items/{partNumber}/bom/export.ods
|
||||
POST /api/items/{partNumber}/bom
|
||||
POST /api/items/{partNumber}/bom/import
|
||||
POST /api/items/{partNumber}/bom/merge
|
||||
PUT /api/items/{partNumber}/bom/{childPartNumber}
|
||||
DELETE /api/items/{partNumber}/bom/{childPartNumber}
|
||||
|
||||
# .kc Metadata
|
||||
GET /api/items/{partNumber}/metadata
|
||||
PUT /api/items/{partNumber}/metadata
|
||||
PATCH /api/items/{partNumber}/metadata/lifecycle
|
||||
PATCH /api/items/{partNumber}/metadata/tags
|
||||
|
||||
# .kc Dependencies
|
||||
GET /api/items/{partNumber}/dependencies
|
||||
GET /api/items/{partNumber}/dependencies/resolve
|
||||
|
||||
# .kc Macros
|
||||
GET /api/items/{partNumber}/macros
|
||||
GET /api/items/{partNumber}/macros/{filename}
|
||||
|
||||
# Part Number Generation
|
||||
POST /api/generate-part-number
|
||||
|
||||
# Sheets
|
||||
POST /api/sheets/diff
|
||||
|
||||
# Settings & Modules (admin)
|
||||
GET /api/modules
|
||||
GET /api/admin/settings
|
||||
GET /api/admin/settings/{module}
|
||||
PUT /api/admin/settings/{module}
|
||||
POST /api/admin/settings/{module}/test
|
||||
```
|
||||
|
||||
### 3.2 `schemas` (required)
|
||||
|
||||
```
|
||||
GET /api/schemas
|
||||
GET /api/schemas/{name}
|
||||
GET /api/schemas/{name}/form
|
||||
POST /api/schemas/{name}/segments/{segment}/values
|
||||
PUT /api/schemas/{name}/segments/{segment}/values/{code}
|
||||
DELETE /api/schemas/{name}/segments/{segment}/values/{code}
|
||||
```
|
||||
|
||||
### 3.3 `storage` (required)
|
||||
|
||||
No dedicated endpoints — storage is consumed internally by file upload/download in `core`. Exposed through admin settings for connection status visibility.
|
||||
|
||||
### 3.4 `auth`
|
||||
|
||||
```
|
||||
# Public (login flow)
|
||||
GET /login
|
||||
POST /login
|
||||
POST /logout
|
||||
GET /auth/oidc
|
||||
GET /auth/callback
|
||||
|
||||
# Authenticated
|
||||
GET /api/auth/me
|
||||
GET /api/auth/tokens
|
||||
POST /api/auth/tokens
|
||||
DELETE /api/auth/tokens/{id}
|
||||
|
||||
# Web UI
|
||||
GET /settings (account info, tokens)
|
||||
POST /settings/tokens
|
||||
POST /settings/tokens/{id}/revoke
|
||||
```
|
||||
|
||||
When `auth` is disabled, all routes are open and a synthetic `dev` admin user is injected (current behavior).
|
||||
|
||||
### 3.5 `projects`
|
||||
|
||||
```
|
||||
GET /api/projects
|
||||
GET /api/projects/{code}
|
||||
GET /api/projects/{code}/items
|
||||
GET /api/projects/{code}/sheet.ods
|
||||
POST /api/projects
|
||||
PUT /api/projects/{code}
|
||||
DELETE /api/projects/{code}
|
||||
|
||||
# Item-project tagging
|
||||
GET /api/items/{partNumber}/projects
|
||||
POST /api/items/{partNumber}/projects
|
||||
DELETE /api/items/{partNumber}/projects/{code}
|
||||
```
|
||||
|
||||
When disabled: project tag endpoints return `404`, project columns are hidden in UI list views, project filter is removed from item search.
|
||||
|
||||
### 3.6 `audit`
|
||||
|
||||
```
|
||||
GET /api/audit/completeness
|
||||
GET /api/audit/completeness/{partNumber}
|
||||
```
|
||||
|
||||
When disabled: audit log table continues to receive writes (it's part of core middleware), but the completeness scoring endpoints and the Audit page in the web UI are hidden. Future: retention policies, export, and compliance reporting endpoints live here.
|
||||
|
||||
### 3.7 `odoo`
|
||||
|
||||
```
|
||||
GET /api/integrations/odoo/config
|
||||
GET /api/integrations/odoo/sync-log
|
||||
PUT /api/integrations/odoo/config
|
||||
POST /api/integrations/odoo/test-connection
|
||||
POST /api/integrations/odoo/sync/push/{partNumber}
|
||||
POST /api/integrations/odoo/sync/pull/{odooId}
|
||||
```
|
||||
|
||||
### 3.8 `freecad`
|
||||
|
||||
No dedicated API endpoints currently. Configures URI scheme and executable path used by the web UI's "Open in Create" links and by CLI operations. Future: client configuration distribution endpoint.
|
||||
|
||||
### 3.9 `jobs`
|
||||
|
||||
```
|
||||
# User-facing
|
||||
GET /api/jobs
|
||||
GET /api/jobs/{jobID}
|
||||
GET /api/jobs/{jobID}/logs
|
||||
POST /api/jobs
|
||||
POST /api/jobs/{jobID}/cancel
|
||||
|
||||
# Job definitions
|
||||
GET /api/job-definitions
|
||||
GET /api/job-definitions/{name}
|
||||
POST /api/job-definitions/reload
|
||||
|
||||
# Runner management (admin)
|
||||
GET /api/runners
|
||||
POST /api/runners
|
||||
DELETE /api/runners/{runnerID}
|
||||
|
||||
# Runner-facing (runner token auth)
|
||||
POST /api/runner/heartbeat
|
||||
POST /api/runner/claim
|
||||
PUT /api/runner/jobs/{jobID}/progress
|
||||
POST /api/runner/jobs/{jobID}/complete
|
||||
POST /api/runner/jobs/{jobID}/fail
|
||||
POST /api/runner/jobs/{jobID}/log
|
||||
PUT /api/runner/jobs/{jobID}/dag
|
||||
```
|
||||
|
||||
### 3.10 `dag`
|
||||
|
||||
```
|
||||
GET /api/items/{partNumber}/dag
|
||||
GET /api/items/{partNumber}/dag/forward-cone/{nodeKey}
|
||||
GET /api/items/{partNumber}/dag/dirty
|
||||
PUT /api/items/{partNumber}/dag
|
||||
POST /api/items/{partNumber}/dag/mark-dirty/{nodeKey}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Disabled Module Behavior
|
||||
|
||||
When a module is disabled:
|
||||
|
||||
1. **API routes** registered by that module return `404 Not Found` with body `{"error": "module '<id>' is not enabled"}`.
|
||||
2. **Web UI** hides the module's navigation entry, page, and any inline UI elements (e.g., project tags on item cards).
|
||||
3. **SSE events** from the module are not broadcast.
|
||||
4. **Background goroutines** (e.g., job timeout sweeper, runner heartbeat checker) are not started.
|
||||
5. **Database tables** are not dropped — they remain for re-enablement. No data loss on disable/enable cycle.
|
||||
|
||||
Implementation: each module's route group is wrapped in a middleware check:
|
||||
|
||||
```go
|
||||
func RequireModule(id string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !modules.IsEnabled(id) {
|
||||
http.Error(w, `{"error":"module '`+id+`' is not enabled"}`, 404)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Configuration Persistence
|
||||
|
||||
### 5.1 Precedence
|
||||
|
||||
```
|
||||
Environment variables (highest — always wins, secrets live here)
|
||||
↓
|
||||
Database overrides (admin UI writes here)
|
||||
↓
|
||||
config.yaml (lowest — bootstrap defaults)
|
||||
```
|
||||
|
||||
### 5.2 Database Table
|
||||
|
||||
```sql
|
||||
-- Migration 014_settings.sql
|
||||
CREATE TABLE settings_overrides (
|
||||
key TEXT PRIMARY KEY, -- dotted path: "auth.ldap.enabled"
|
||||
value JSONB NOT NULL, -- typed value
|
||||
updated_by TEXT NOT NULL, -- username
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE module_state (
|
||||
module_id TEXT PRIMARY KEY, -- "auth", "projects", etc.
|
||||
enabled BOOLEAN NOT NULL,
|
||||
updated_by TEXT NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
```
|
||||
|
||||
### 5.3 Load Sequence
|
||||
|
||||
On startup:
|
||||
|
||||
1. Parse `config.yaml` into Go config struct.
|
||||
2. Query `settings_overrides` — merge each key into the struct using dotted path resolution.
|
||||
3. Apply environment variable overrides (existing `SILO_*` vars).
|
||||
4. Query `module_state` — override default enabled/disabled from YAML.
|
||||
5. Validate module dependencies.
|
||||
6. Register only enabled modules' route groups.
|
||||
7. Start only enabled modules' background goroutines.
|
||||
|
||||
### 5.4 Runtime Updates
|
||||
|
||||
When an admin saves settings via `PUT /api/admin/settings/{module}`:
|
||||
|
||||
1. Validate the payload against the module's config schema.
|
||||
2. Write changed keys to `settings_overrides`.
|
||||
3. Update `module_state` if `enabled` changed.
|
||||
4. Apply changes to the in-memory config (hot reload where safe).
|
||||
5. Broadcast `settings.changed` SSE event with `{module, enabled, changed_keys}`.
|
||||
6. For changes that require restart (e.g., `server.port`, `database.*`), return a `restart_required: true` flag in the response. The UI shows a banner.
|
||||
|
||||
### 5.5 What Requires Restart
|
||||
|
||||
| Config Area | Hot Reload | Restart Required |
|
||||
|-------------|-----------|------------------|
|
||||
| Module enable/disable | Yes | No |
|
||||
| `auth.*` provider toggles | Yes | No |
|
||||
| `auth.cors.allowed_origins` | Yes | No |
|
||||
| `odoo.*` connection settings | Yes | No |
|
||||
| `freecad.*` | Yes | No |
|
||||
| `jobs.*` timeouts, directory | Yes | No |
|
||||
| `server.host`, `server.port` | No | Yes |
|
||||
| `database.*` | No | Yes |
|
||||
| `storage.*` | No | Yes |
|
||||
| `schemas.directory` | No | Yes |
|
||||
|
||||
---
|
||||
|
||||
## 6. Public Module Discovery Endpoint
|
||||
|
||||
```
|
||||
GET /api/modules
|
||||
```
|
||||
|
||||
**No authentication required.** Clients need this pre-login to know whether OIDC is available, whether projects exist, etc.
|
||||
|
||||
### 6.1 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"modules": {
|
||||
"core": {
|
||||
"enabled": true,
|
||||
"required": true,
|
||||
"name": "Core PDM",
|
||||
"version": "0.2"
|
||||
},
|
||||
"schemas": {
|
||||
"enabled": true,
|
||||
"required": true,
|
||||
"name": "Schemas"
|
||||
},
|
||||
"storage": {
|
||||
"enabled": true,
|
||||
"required": true,
|
||||
"name": "Storage"
|
||||
},
|
||||
"auth": {
|
||||
"enabled": true,
|
||||
"required": false,
|
||||
"name": "Authentication",
|
||||
"config": {
|
||||
"local_enabled": true,
|
||||
"ldap_enabled": true,
|
||||
"oidc_enabled": true,
|
||||
"oidc_issuer_url": "https://keycloak.example.com/realms/silo"
|
||||
}
|
||||
},
|
||||
"projects": {
|
||||
"enabled": true,
|
||||
"required": false,
|
||||
"name": "Projects"
|
||||
},
|
||||
"audit": {
|
||||
"enabled": true,
|
||||
"required": false,
|
||||
"name": "Audit"
|
||||
},
|
||||
"odoo": {
|
||||
"enabled": false,
|
||||
"required": false,
|
||||
"name": "Odoo ERP"
|
||||
},
|
||||
"freecad": {
|
||||
"enabled": true,
|
||||
"required": false,
|
||||
"name": "Create Integration",
|
||||
"config": {
|
||||
"uri_scheme": "silo"
|
||||
}
|
||||
},
|
||||
"jobs": {
|
||||
"enabled": false,
|
||||
"required": false,
|
||||
"name": "Job Queue"
|
||||
},
|
||||
"dag": {
|
||||
"enabled": false,
|
||||
"required": false,
|
||||
"name": "Dependency DAG",
|
||||
"depends_on": ["jobs"]
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"version": "0.2",
|
||||
"read_only": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `config` sub-object exposes only public, non-secret metadata needed by clients. Never includes passwords, tokens, or secret keys.
|
||||
|
||||
---
|
||||
|
||||
## 7. Admin Settings Endpoints
|
||||
|
||||
### 7.1 Get All Settings
|
||||
|
||||
```
|
||||
GET /api/admin/settings
|
||||
Authorization: Bearer <admin token>
|
||||
```
|
||||
|
||||
Returns full config grouped by module with secrets redacted:
|
||||
|
||||
```json
|
||||
{
|
||||
"core": {
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"base_url": "https://silo.example.com",
|
||||
"read_only": false
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"directory": "/etc/silo/schemas",
|
||||
"default": "kindred-rd"
|
||||
},
|
||||
"storage": {
|
||||
"endpoint": "minio:9000",
|
||||
"bucket": "silo-files",
|
||||
"access_key": "****",
|
||||
"secret_key": "****",
|
||||
"use_ssl": false,
|
||||
"region": "us-east-1",
|
||||
"status": "connected"
|
||||
},
|
||||
"database": {
|
||||
"host": "postgres",
|
||||
"port": 5432,
|
||||
"name": "silo",
|
||||
"user": "silo",
|
||||
"password": "****",
|
||||
"sslmode": "disable",
|
||||
"max_connections": 10,
|
||||
"status": "connected"
|
||||
},
|
||||
"auth": {
|
||||
"enabled": true,
|
||||
"session_secret": "****",
|
||||
"local": { "enabled": true },
|
||||
"ldap": {
|
||||
"enabled": true,
|
||||
"url": "ldaps://ipa.example.com",
|
||||
"base_dn": "dc=kindred,dc=internal",
|
||||
"user_search_dn": "cn=users,cn=accounts,dc=kindred,dc=internal",
|
||||
"bind_password": "****",
|
||||
"role_mapping": { "...": "..." }
|
||||
},
|
||||
"oidc": {
|
||||
"enabled": true,
|
||||
"issuer_url": "https://keycloak.example.com/realms/silo",
|
||||
"client_id": "silo",
|
||||
"client_secret": "****",
|
||||
"redirect_url": "https://silo.example.com/auth/callback"
|
||||
},
|
||||
"cors": { "allowed_origins": ["https://silo.example.com"] }
|
||||
},
|
||||
"projects": { "enabled": true },
|
||||
"audit": { "enabled": true },
|
||||
"odoo": { "enabled": false, "url": "", "database": "", "username": "" },
|
||||
"freecad": { "uri_scheme": "silo", "executable": "" },
|
||||
"jobs": {
|
||||
"enabled": false,
|
||||
"directory": "/etc/silo/jobdefs",
|
||||
"runner_timeout": 90,
|
||||
"job_timeout_check": 30,
|
||||
"default_priority": 100
|
||||
},
|
||||
"dag": { "enabled": false }
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 Get Module Settings
|
||||
|
||||
```
|
||||
GET /api/admin/settings/{module}
|
||||
```
|
||||
|
||||
Returns just the module's config block.
|
||||
|
||||
### 7.3 Update Module Settings
|
||||
|
||||
```
|
||||
PUT /api/admin/settings/{module}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
"ldap": {
|
||||
"enabled": true,
|
||||
"url": "ldaps://ipa.example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"updated": ["auth.ldap.enabled", "auth.ldap.url"],
|
||||
"restart_required": false
|
||||
}
|
||||
```
|
||||
|
||||
### 7.4 Test Connectivity
|
||||
|
||||
```
|
||||
POST /api/admin/settings/{module}/test
|
||||
```
|
||||
|
||||
Available for modules with external connections:
|
||||
|
||||
| Module | Test Action |
|
||||
|--------|------------|
|
||||
| `storage` | Ping MinIO, verify bucket exists |
|
||||
| `auth` (ldap) | Attempt LDAP bind with configured credentials |
|
||||
| `auth` (oidc) | Fetch OIDC discovery document from issuer URL |
|
||||
| `odoo` | Attempt XML-RPC connection to Odoo |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "LDAP bind successful",
|
||||
"latency_ms": 42
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Config YAML Changes
|
||||
|
||||
The existing `config.yaml` gains a `modules` section. Existing top-level keys remain for backward compatibility — the module system reads from both locations.
|
||||
|
||||
```yaml
|
||||
# Existing keys (unchanged, still work)
|
||||
server:
|
||||
host: "0.0.0.0"
|
||||
port: 8080
|
||||
|
||||
database:
|
||||
host: postgres
|
||||
port: 5432
|
||||
name: silo
|
||||
user: silo
|
||||
password: silodev
|
||||
sslmode: disable
|
||||
|
||||
storage:
|
||||
endpoint: minio:9000
|
||||
bucket: silo-files
|
||||
access_key: silominio
|
||||
secret_key: silominiosecret
|
||||
use_ssl: false
|
||||
|
||||
schemas:
|
||||
directory: /etc/silo/schemas
|
||||
|
||||
auth:
|
||||
enabled: true
|
||||
session_secret: change-me
|
||||
local:
|
||||
enabled: true
|
||||
|
||||
# New: explicit module toggles (optional, defaults shown)
|
||||
modules:
|
||||
projects:
|
||||
enabled: true
|
||||
audit:
|
||||
enabled: true
|
||||
odoo:
|
||||
enabled: false
|
||||
freecad:
|
||||
enabled: true
|
||||
uri_scheme: silo
|
||||
jobs:
|
||||
enabled: false
|
||||
directory: /etc/silo/jobdefs
|
||||
runner_timeout: 90
|
||||
job_timeout_check: 30
|
||||
default_priority: 100
|
||||
dag:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
If a module is not listed under `modules:`, its default enabled state from Section 2.2 applies. The `auth.enabled` field continues to control the `auth` module (no duplication under `modules:`).
|
||||
|
||||
---
|
||||
|
||||
## 9. SSE Events
|
||||
|
||||
```
|
||||
settings.changed {module, enabled, changed_keys[], updated_by}
|
||||
```
|
||||
|
||||
Broadcast on any admin settings change. The web UI listens for this to:
|
||||
|
||||
- Show/hide navigation entries when modules are toggled.
|
||||
- Display a "Settings updated by another admin" toast.
|
||||
- Show a "Restart required" banner when flagged.
|
||||
|
||||
---
|
||||
|
||||
## 10. Web UI — Admin Settings Page
|
||||
|
||||
The Settings page (`/settings`) is restructured into sections:
|
||||
|
||||
### 10.1 Existing (unchanged)
|
||||
|
||||
- **Account** — username, display name, email, auth source, role badge.
|
||||
- **API Tokens** — create, list, revoke.
|
||||
|
||||
### 10.2 New: Module Configuration (admin only)
|
||||
|
||||
Visible only to admin users. Each module gets a collapsible card:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ [toggle] Authentication [status] │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ── Local Auth ──────────────────────────────────── │
|
||||
│ Enabled: [toggle] │
|
||||
│ │
|
||||
│ ── LDAP / FreeIPA ──────────────────────────────── │
|
||||
│ Enabled: [toggle] │
|
||||
│ URL: [ldaps://ipa.example.com ] │
|
||||
│ Base DN: [dc=kindred,dc=internal ] [Test] │
|
||||
│ │
|
||||
│ ── OIDC / Keycloak ────────────────────────────── │
|
||||
│ Enabled: [toggle] │
|
||||
│ Issuer URL: [https://keycloak.example.com] [Test] │
|
||||
│ Client ID: [silo ] │
|
||||
│ │
|
||||
│ ── CORS ────────────────────────────────────────── │
|
||||
│ Allowed Origins: [tag input] │
|
||||
│ │
|
||||
│ [Save] │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Module cards for required modules (`core`, `schemas`, `storage`) show their status and config but have no enable/disable toggle.
|
||||
|
||||
Status indicators per module:
|
||||
|
||||
| Status | Badge | Meaning |
|
||||
|--------|-------|---------|
|
||||
| Active | `green` | Enabled and operational |
|
||||
| Disabled | `overlay1` | Toggled off |
|
||||
| Error | `red` | Enabled but connectivity or config issue |
|
||||
| Setup Required | `yellow` | Enabled but missing required config (e.g., LDAP URL empty) |
|
||||
|
||||
### 10.3 Infrastructure Section (admin, read-only)
|
||||
|
||||
Shows connection status for required infrastructure:
|
||||
|
||||
- **Database** — host, port, name, connection pool usage, status badge.
|
||||
- **Storage** — endpoint, bucket, SSL, status badge.
|
||||
|
||||
These are read-only in the UI (setup-only via YAML/env). The "Test" button is available to verify connectivity.
|
||||
|
||||
---
|
||||
|
||||
## 11. Implementation Order
|
||||
|
||||
1. **Migration 014** — `settings_overrides` and `module_state` tables.
|
||||
2. **Config loader refactor** — YAML → DB merge → env override pipeline.
|
||||
3. **Module registry** — Go struct defining all modules with metadata, dependencies, defaults.
|
||||
4. **`GET /api/modules`** — public endpoint, no auth.
|
||||
5. **`RequireModule` middleware** — gate route groups by module state.
|
||||
6. **Admin settings API** — `GET/PUT /api/admin/settings/{module}`, test endpoints.
|
||||
7. **Web UI settings page** — module cards with toggles, config forms, test buttons.
|
||||
8. **SSE integration** — `settings.changed` event broadcast.
|
||||
|
||||
---
|
||||
|
||||
## 12. Future Considerations
|
||||
|
||||
- **Module manifest format** — per ROADMAP.md, each module will eventually declare routes, views, hooks, and permissions via a manifest. This spec covers the runtime module registry; the manifest format is TBD.
|
||||
- **Custom modules** — third-party modules that register against the endpoint registry. Requires the manifest contract and a plugin loading mechanism.
|
||||
- **Per-module permissions** — beyond the current role hierarchy, modules may define fine-grained scopes (e.g., `jobs:admin`, `dag:write`).
|
||||
- **Location & Inventory module** — when the Location/Inventory API is implemented (tables already exist), it becomes a new optional module.
|
||||
- **Notifications module** — per ROADMAP.md Tier 1, notifications/subscriptions will be a dedicated module.
|
||||
|
||||
---
|
||||
|
||||
## 13. References
|
||||
|
||||
- [CONFIGURATION.md](CONFIGURATION.md) — Current config reference
|
||||
- [ROADMAP.md](ROADMAP.md) — Module manifest, API endpoint registry
|
||||
- [AUTH.md](AUTH.md) — Authentication architecture
|
||||
- [WORKERS.md](WORKERS.md) — Job queue system
|
||||
- [DAG.md](DAG.md) — Dependency DAG specification
|
||||
- [SPECIFICATION.md](SPECIFICATION.md) — Full endpoint listing
|
||||
@@ -1,40 +1,288 @@
|
||||
# Silo Roadmap
|
||||
# Silo Platform Roadmap
|
||||
|
||||
**Version:** 1.1
|
||||
**Date:** February 2026
|
||||
**Purpose:** Project inventory, SOLIDWORKS PDM gap analysis, and development roadmap
|
||||
**Version:** 2.0
|
||||
**Date:** February 2026
|
||||
|
||||
Silo is the server component of the Kindred ecosystem. Its core function is storing and version-controlling engineering data (parts, assemblies, BOMs). This roadmap describes the expansion of Silo from a PDM server into a modular platform -- comparable to how Gitea/GitHub extend Git hosting with Actions, Wikis, Packages, and webhooks.
|
||||
|
||||
For a detailed comparison against SOLIDWORKS PDM, see [GAP_ANALYSIS.md](GAP_ANALYSIS.md).
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
## Guiding Principles
|
||||
|
||||
1. [Executive Summary](#executive-summary)
|
||||
2. [Current Project Inventory](#current-project-inventory)
|
||||
3. [SOLIDWORKS PDM Gap Analysis](#solidworks-pdm-gap-analysis)
|
||||
4. [Feature Roadmap](#feature-roadmap)
|
||||
5. [Implementation Phases](#implementation-phases)
|
||||
- **Modular architecture.** Every capability beyond core PDM is a module. Modules register against a central API endpoint registry and declare their menu entries, views, dependencies, and routes via a module manifest.
|
||||
- **Odoo-aligned UX.** The web UI follows Odoo's navigation patterns: a top-level app launcher grid, breadcrumb navigation (`Module > List > Record > Sub-view`), and standard view types (list, form, kanban, calendar, pivot). This alignment provides a familiar experience for shops already using Odoo as their ERP, and a clean integration path for those who adopt it later.
|
||||
- **Open by default.** Silo and all modules are open-source. Enterprise customers can fork, extend, and self-host. Developer tools for building and distributing custom Create forks are available to everyone, not just Kindred.
|
||||
- **Odoo as reference ERP.** For shops on Odoo, a bridge module syncs Silo data to Odoo models (`mrp.bom`, `mrp.production`, `quality.check`, etc.). For shops on other ERPs, the open API serves as a documented integration surface. Silo's web UI is fully self-sufficient with no ERP dependency required.
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
## Foundational Contracts
|
||||
|
||||
Silo is an R&D-oriented item database and part management system. It provides configurable part number generation, revision tracking, BOM management, and file versioning through MinIO storage. CAD integration (FreeCAD workbench, LibreOffice Calc extension) is maintained in separate repositories ([silo-mod](https://git.kindred-systems.com/kindred/silo-mod), [silo-calc](https://git.kindred-systems.com/kindred/silo-calc)).
|
||||
### The .kc File Format
|
||||
|
||||
This document compares Silo's current capabilities against SOLIDWORKS PDM—the industry-leading product data management solution—to identify gaps and prioritize future development.
|
||||
Silo introduces the `.kc` file format as an enhanced superset of FreeCAD's `.fcstd`. Both are ZIP bundles. A `.kc` file contains everything an `.fcstd` does, plus a `silo/` directory with platform metadata.
|
||||
|
||||
### Key Differentiators
|
||||
#### Standard FCStd contents (preserved as-is)
|
||||
|
||||
| Aspect | Silo | SOLIDWORKS PDM |
|
||||
|--------|------|----------------|
|
||||
| **Target CAD** | FreeCAD / Kindred Create (open source) | SOLIDWORKS (proprietary) |
|
||||
| **Part Numbering** | Schema-as-configuration (YAML) | Fixed format with some customization |
|
||||
| **Licensing** | Open source / Kindred Proprietary | Commercial ($3,000-$10,000+ per seat) |
|
||||
| **Storage** | PostgreSQL + MinIO (S3-compatible) | SQL Server + File Archive |
|
||||
| **Philosophy** | R&D-oriented, lightweight | Enterprise-grade, comprehensive |
|
||||
- `Document.xml`, `GuiDocument.xml`
|
||||
- BREP geometry files (`.brp`)
|
||||
- `thumbnails/`
|
||||
|
||||
#### Added .kc entries
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `silo/manifest.json` | Silo instance origin, part UUID, revision hash, .kc schema version |
|
||||
| `silo/metadata.json` | Custom schema field values, tags, lifecycle state |
|
||||
| `silo/history.json` | Local revision log (lightweight; full history is server-side) |
|
||||
| `silo/approvals.json` | ECO/approval state snapshot |
|
||||
| `silo/dependencies.json` | Assembly link references by Silo UUID (not filepath) |
|
||||
| `silo/macros/` | Embedded macro references or inline scripts bound to this part |
|
||||
| `silo/inspection/` | GD&T annotations, tolerance data, CMM linkage metadata |
|
||||
| `silo/thumbnails/` | Silo-generated renderings (separate from FreeCAD's built-in thumbnail) |
|
||||
|
||||
#### Interoperability
|
||||
|
||||
- **FCStd -> Silo:** On import, the `silo/` directory is generated with defaults. A UUID is assigned and the user is prompted for schema fields.
|
||||
- **Silo -> FCStd:** On export, the `silo/` directory is stripped. The remaining contents are a valid `.fcstd`.
|
||||
- **Round-trip safety:** FreeCAD ignores the `silo/` directory on save, so there is no risk of FreeCAD corrupting Silo metadata.
|
||||
- **Schema versioning:** `silo/manifest.json` carries a format version for forward-compatible migrations.
|
||||
|
||||
### Module Manifest
|
||||
|
||||
Each module ships a manifest declaring its integration surface:
|
||||
|
||||
```
|
||||
id, name, version, description
|
||||
dependencies (other module IDs)
|
||||
menu_entries (app launcher icon, label, route)
|
||||
view_declarations (list, form, kanban, etc.)
|
||||
api_routes (REST endpoints the module registers)
|
||||
hooks (events the module listens to or emits)
|
||||
permissions (required roles/scopes)
|
||||
```
|
||||
|
||||
The exact format (JSON, TOML, or Python-based a la Odoo's `__manifest__.py`) is TBD. The contract is: a module is anything that provides a valid manifest and registers against the endpoint registry.
|
||||
|
||||
### Web UI Shell
|
||||
|
||||
The Silo web application provides the chrome that all modules render within.
|
||||
|
||||
- **App launcher:** Top-level grid of installed module icons. Driven by the API endpoint registry -- only enabled modules appear. Disabled modules show greyed with an "Enable" action for discoverability.
|
||||
- **Breadcrumbs:** Every view follows `Module > List > Record > Sub-view`. Consistent across all modules.
|
||||
- **View types:** List, form, kanban, calendar, pivot/reporting. Modules declare supported views in their manifest.
|
||||
- **Schema-driven forms:** The user-customizable schema engine maps directly to form views, enabling end-users to define part metadata fields through the web UI without code changes.
|
||||
|
||||
---
|
||||
|
||||
## Current Project Inventory
|
||||
## Dependency Tiers
|
||||
|
||||
Modules are organized into tiers based on what they depend on. Lower tiers must be stable before higher tiers are built.
|
||||
|
||||
### Tier 0 -- Foundation
|
||||
|
||||
Everything depends on these. They define what Silo *is*.
|
||||
|
||||
| Component | Description | Status |
|
||||
|-----------|-------------|--------|
|
||||
| **Core Silo** | Part/assembly storage, version control, auth, base REST API | Complete |
|
||||
| **.kc Format Spec** | File format contract between Create and Silo | Complete |
|
||||
| **API Endpoint Registry** | Module discovery, dynamic UI rendering, health checks | Not Started |
|
||||
| **Web UI Shell** | App launcher, breadcrumbs, view framework, module rendering | Partial |
|
||||
| **Python Scripting Engine** | Server-side hook execution, module extension point | Not Started |
|
||||
| **Job Queue Infrastructure** | Redis/NATS shared async service for all compute modules | Not Started |
|
||||
|
||||
### Tier 1 -- Core Services
|
||||
|
||||
Broad downstream dependencies. These should be built early because retrofitting is painful.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **Headless Create** | API-driven FreeCAD instance for file manipulation, geometry queries, format conversion, rendering | Core Silo, Job Queue | Not Started |
|
||||
| **Notifications & Subscriptions** | Per-part watch lists, lifecycle event hooks, webhook delivery | Core Silo, Registry | Not Started |
|
||||
| **Audit Trail / Compliance** | ITAR, ISO 9001, AS9100 traceability; module-level event journaling | Core Silo | Partial |
|
||||
|
||||
### Tier 2 -- File Intelligence & Collaboration
|
||||
|
||||
High-visibility features. Mostly low-hanging fruit once Tier 1 is solid.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **Intelligent FCStd Diffing** | XML-based structural diff of .kc bundles | Headless Create | Not Started |
|
||||
| **Thumbnail Generation** | Auto-rendered part/assembly previews | Headless Create | Not Started |
|
||||
| **Macro Store** | Shared macro library across Create instances | Core Silo, Registry | Not Started |
|
||||
| **Theme & Addon Manager** | Centralized distribution of UI themes and workbench addons | Core Silo, Registry | Not Started |
|
||||
| **User-Customizable Schemas** | End-user defined part/form metadata via web UI | Core Silo, Scripting Engine | Not Started |
|
||||
|
||||
### Tier 3 -- Compute
|
||||
|
||||
Heavy async workloads. All route through the shared job queue.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **Batch Jobs (CPU/GPU)** | FEA, CFD, rendering, bulk export | Job Queue, Headless Create | Not Started |
|
||||
| **AI Broker** | LLM tasks (Ollama), GNN constraint optimization, appearance AI | Job Queue | Not Started |
|
||||
| **Reporting & Analytics** | Part reuse, revision frequency, compute usage dashboards, cost roll-ups | Audit Trail, Core Silo | Not Started |
|
||||
|
||||
### Tier 4 -- Engineering Workflow
|
||||
|
||||
Process modules that formalize how engineering work moves through an organization.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **Approval / ECO Workflow** | Engineering change orders, multi-stage review gates, digital signatures | Notifications, Audit Trail, Schemas | Not Started |
|
||||
| **Shop Floor Drawing Distribution** | Controlled push-to-production drawings; web-based appliance displays on the floor | Headless Create, Approval Workflow | Not Started |
|
||||
| **Import/Export Bridge** | STEP, IGES, 3MF connectors; SOLIDWORKS migration tooling; ERP adapters | Headless Create | Not Started |
|
||||
| **Multi-tenant / Org Management** | Org boundaries, role-based permissioning, storage quotas | Core Auth, Audit Trail | Not Started |
|
||||
|
||||
### Tier 5 -- Manufacturing & Quality
|
||||
|
||||
Deep domain modules. Heavy spec work required independent of software dependencies.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **MES Module** | Manufacturing execution -- internal module or bridge to external MES | Approval Workflow, Schemas, Shop Floor Drawings | Not Started |
|
||||
| **Quality / Tolerance Stackup** | Inspection data ingestion, CMM device linking, statistical tolerance analysis, material mapping | Schemas, Import Bridge | Not Started |
|
||||
| **Inspection Plan Generator** | Auto-generate CMM programs or inspection checklists from GD&T drawings | Headless Create, Quality Module | Not Started |
|
||||
| **BIM Inventory / Receiving** | Live facility model with real-time inventory location, explorable in a custom BIM-MES workbench in Create | Custom BIM-MES Workbench, Schemas, Notifications | Not Started |
|
||||
|
||||
### Tier 6 -- Platform & Ecosystem
|
||||
|
||||
Modules that serve the broader community and long-horizon use cases.
|
||||
|
||||
| Module | Description | Depends On | Status |
|
||||
|--------|-------------|------------|--------|
|
||||
| **Developer Tools** | Managed Gitea instance for in-house Create fork development; CI/CD to build and distribute fork updates to configured clients | Tier 0-1 stability | Not Started |
|
||||
| **Digital Twin Sync** | Live sensor data mapped onto BIM/assembly models; operational monitoring | BIM Inventory, Reporting | Not Started |
|
||||
| **ERP Adapters (Odoo, SAP, etc.)** | Bidirectional sync of parts, BOMs, ECOs, production orders to external ERP | Import/Export Bridge, MES, Schemas | Partial (Odoo stubs) |
|
||||
|
||||
---
|
||||
|
||||
## Near-Term Priorities
|
||||
|
||||
These are the concrete tasks that map to Tier 0 completion and the first steps into Tier 1. They replace the older Phase 1-6 calendar-based timelines.
|
||||
|
||||
### Tier 0 Completion
|
||||
|
||||
Complete MVP and stabilize core functionality.
|
||||
|
||||
| Task | Description | Status |
|
||||
|------|-------------|--------|
|
||||
| Unit test suite | Core API, database, partnum, file, CSV/ODS handler tests | Partial (~40%) |
|
||||
| Date segment type | Implement `date` segment with strftime-style formatting | Not Started |
|
||||
| Part number validation | Validate format against schema on creation | Not Started |
|
||||
| Location CRUD API | Expose location hierarchy via REST | Not Started |
|
||||
| Inventory API | Expose inventory operations via REST | Not Started |
|
||||
|
||||
**Success metrics:**
|
||||
- All existing tests pass
|
||||
- File upload/download works end-to-end
|
||||
- FreeCAD users can checkout, modify, commit parts
|
||||
|
||||
### Multi-User Enablement
|
||||
|
||||
Enable team collaboration (feeds into Tier 1 and Tier 4).
|
||||
|
||||
| Task | Description | Status |
|
||||
|------|-------------|--------|
|
||||
| Check-out locking | Pessimistic locks with timeout | Not Started |
|
||||
| User/group management | Create, assign, manage users and groups | Not Started |
|
||||
| Folder permissions | Read/write/delete per folder hierarchy | Not Started |
|
||||
|
||||
**Success metrics:**
|
||||
- 5+ concurrent users supported
|
||||
- No data corruption under concurrent access
|
||||
- Audit log captures all modifications
|
||||
|
||||
### Workflow Engine
|
||||
|
||||
Implement engineering change processes (Tier 4: Approval/ECO Workflow).
|
||||
|
||||
| Task | Description | Status |
|
||||
|------|-------------|--------|
|
||||
| Workflow designer | YAML-defined state machines | Not Started |
|
||||
| State transitions | Configurable transition rules with permissions | Not Started |
|
||||
| Approval workflows | Single and parallel approver gates | Not Started |
|
||||
| Email notifications | SMTP integration for alerts on state changes | Not Started |
|
||||
|
||||
**Success metrics:**
|
||||
- Engineering change process completable in Silo
|
||||
- Email notifications delivered reliably
|
||||
- Workflow state visible in web UI
|
||||
|
||||
### Search & Discovery
|
||||
|
||||
Improve findability and navigation (Tier 0 Web UI Shell).
|
||||
|
||||
| Task | Description | Status |
|
||||
|------|-------------|--------|
|
||||
| Advanced search UI | Web interface with filters and operators | Not Started |
|
||||
| Saved searches | User-defined query favorites | Not Started |
|
||||
|
||||
**Success metrics:**
|
||||
- Search returns results in <2 seconds
|
||||
- Where-used queries complete in <5 seconds
|
||||
|
||||
---
|
||||
|
||||
## Gap Summary
|
||||
|
||||
For full SOLIDWORKS PDM comparison tables, see [GAP_ANALYSIS.md Appendix C](GAP_ANALYSIS.md#appendix-c-solidworks-pdm-comparison).
|
||||
|
||||
### Completed (Previously Critical/High)
|
||||
|
||||
1. ~~User authentication~~ -- local, LDAP, OIDC
|
||||
2. ~~Role-based permissions~~ -- 3-tier role model (admin/editor/viewer)
|
||||
3. ~~Audit trail~~ -- audit_log table with completeness scoring
|
||||
4. ~~Where-used search~~ -- reverse parent lookup API
|
||||
5. ~~Multi-level BOM API~~ -- recursive expansion with configurable depth
|
||||
6. ~~BOM export~~ -- CSV and ODS formats
|
||||
|
||||
### Critical Gaps (Required for Team Use)
|
||||
|
||||
1. **Workflow engine** -- state machines with transitions and approvals
|
||||
2. **Check-out locking** -- pessimistic locking for CAD files
|
||||
|
||||
### High Priority Gaps (Significant Value)
|
||||
|
||||
1. **Email notifications** -- alert users on state changes
|
||||
2. **Web UI search** -- advanced search interface with saved searches
|
||||
3. **Folder/state permissions** -- granular access control beyond role model
|
||||
|
||||
### Medium Priority Gaps (Nice to Have)
|
||||
|
||||
1. **Saved searches** -- frequently used queries
|
||||
2. **File preview/thumbnails** -- visual browsing
|
||||
3. **Reporting** -- activity and inventory reports
|
||||
4. **Scheduled tasks** -- background automation
|
||||
5. **BOM comparison** -- revision diff for assemblies
|
||||
|
||||
---
|
||||
|
||||
## Priority Notes
|
||||
|
||||
- **Headless Create** is the single highest-leverage Tier 1 item. It unblocks diffing, thumbnails, batch export, drawing distribution, and inspection plan generation.
|
||||
- **Audit Trail** is unglamorous but critical to build early. Retrofitting compliance logging after modules ship is expensive and error-prone.
|
||||
- **Tier 2** delivers visible, demo-able value quickly -- diffing, thumbnails, and the macro store are features users immediately understand.
|
||||
- **Tiers 5-6** carry heavy domain complexity. They need detailed specification and industry consultation well before implementation begins.
|
||||
- The **.kc format** and **module manifest** are the two foundational contracts. Getting these right determines how cleanly everything above them composes.
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Module manifest format** -- JSON, TOML, or Python-based? Tradeoffs between simplicity and expressiveness.
|
||||
2. **.kc thumbnail policy** -- Single canonical thumbnail vs. multi-view renders. Impacts file size and generation cost.
|
||||
3. **Job queue technology** -- Redis Streams vs. NATS. Redis is already in the stack; NATS offers better pub/sub semantics for event-driven modules.
|
||||
4. **Headless Create deployment** -- Sidecar container per Silo instance, or pool of workers behind the job queue?
|
||||
5. **BIM-MES workbench scope** -- How much of FreeCAD BIM is reusable vs. needs to be purpose-built for inventory/facility modeling?
|
||||
6. **Offline .kc workflow** -- How much of the `silo/` metadata is authoritative when disconnected? Reconciliation strategy on reconnect.
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: Current Project Inventory
|
||||
|
||||
### Implemented Features (MVP Complete)
|
||||
|
||||
@@ -65,7 +313,7 @@ This document compares Silo's current capabilities against SOLIDWORKS PDM—the
|
||||
- Rollback functionality
|
||||
|
||||
#### File Management
|
||||
- MinIO integration with versioning
|
||||
- Filesystem-based file storage
|
||||
- File upload/download via REST API
|
||||
- SHA256 checksums for integrity
|
||||
- Storage path: `items/{partNumber}/rev{N}.FCStd`
|
||||
@@ -99,7 +347,7 @@ This document compares Silo's current capabilities against SOLIDWORKS PDM—the
|
||||
- Session management (PostgreSQL-backed, 24h lifetime)
|
||||
- CSRF protection (nosurf on web forms)
|
||||
- Middleware: logging, CORS, recovery, request ID
|
||||
- Web UI — React SPA (Vite + TypeScript, Catppuccin Mocha theme)
|
||||
- Web UI -- React SPA (Vite + TypeScript, Catppuccin Mocha theme)
|
||||
- Fuzzy search
|
||||
- Health and readiness probes
|
||||
|
||||
@@ -123,304 +371,19 @@ This document compares Silo's current capabilities against SOLIDWORKS PDM—the
|
||||
| Part number validation | Not started | API accepts but doesn't validate format |
|
||||
| Location hierarchy CRUD | Schema only | Tables exist, no API endpoints |
|
||||
| Inventory tracking | Schema only | Tables exist, no API endpoints |
|
||||
| Unit tests | Partial | 9 Go test files across api, db, ods, partnum, schema packages |
|
||||
|
||||
### Infrastructure Status
|
||||
|
||||
| Component | Status |
|
||||
|-----------|--------|
|
||||
| PostgreSQL | Running (psql.example.internal) |
|
||||
| MinIO | Configured in Docker Compose |
|
||||
| Silo API Server | Builds successfully |
|
||||
| Docker Compose | Complete (dev and production) |
|
||||
| systemd service | Unit file and env template ready |
|
||||
| Deployment scripts | setup-host, deploy, init-db, setup-ipa-nginx |
|
||||
| Unit tests | Partial | 11 Go test files across api, db, ods, partnum, schema packages |
|
||||
|
||||
---
|
||||
|
||||
## SOLIDWORKS PDM Gap Analysis
|
||||
## Appendix B: Phase 1 Detailed Tasks
|
||||
|
||||
This section compares Silo's capabilities against SOLIDWORKS PDM features. Gaps are categorized by priority and implementation complexity.
|
||||
|
||||
### Legend
|
||||
- **Silo Status:** Full / Partial / None
|
||||
- **Priority:** Critical / High / Medium / Low
|
||||
- **Complexity:** Simple / Moderate / Complex
|
||||
|
||||
---
|
||||
|
||||
### 1. Version Control & Revision Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Check-in/check-out | Full pessimistic locking | None | High | Moderate |
|
||||
| Version history | Complete with branching | Full (linear) | - | - |
|
||||
| Revision labels | A, B, C or custom schemes | Full (custom labels) | - | - |
|
||||
| Rollback/restore | Full | Full | - | - |
|
||||
| Compare revisions | Visual + metadata diff | Metadata diff only | Medium | Complex |
|
||||
| Get Latest Revision | One-click retrieval | Partial (API only) | Medium | Simple |
|
||||
|
||||
**Gap Analysis:**
|
||||
Silo lacks pessimistic locking (check-out), which is critical for multi-user CAD environments where file merging is impractical. Visual diff comparison would require FreeCAD integration for CAD file visualization.
|
||||
|
||||
---
|
||||
|
||||
### 2. Workflow Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Custom workflows | Full visual designer | None | Critical | Complex |
|
||||
| State transitions | Configurable with permissions | Basic (status field only) | Critical | Complex |
|
||||
| Parallel approvals | Multiple approvers required | None | High | Complex |
|
||||
| Automatic transitions | Timer/condition-based | None | Medium | Moderate |
|
||||
| Email notifications | On state change | None | High | Moderate |
|
||||
| ECO process | Built-in change management | None | High | Complex |
|
||||
| Child state conditions | Block parent if children invalid | None | Medium | Moderate |
|
||||
|
||||
**Gap Analysis:**
|
||||
Workflow management is the largest functional gap. SOLIDWORKS PDM offers sophisticated state machines with parallel approvals, automatic transitions, and deep integration with engineering change processes. Silo currently has only a simple status field (draft/review/released/obsolete) with no transition rules or approval processes.
|
||||
|
||||
---
|
||||
|
||||
### 3. User Management & Security
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| User authentication | Windows AD, LDAP | Full (local, LDAP, OIDC) | - | - |
|
||||
| Role-based permissions | Granular per folder/state | Partial (3-tier role model) | Medium | Moderate |
|
||||
| Group management | Full | None | Medium | Moderate |
|
||||
| Folder permissions | Read/write/delete per folder | None | Medium | Moderate |
|
||||
| State permissions | Actions allowed per state | None | High | Moderate |
|
||||
| Audit trail | Complete action logging | Full | - | - |
|
||||
| Private files | Pre-check-in visibility control | None | Low | Simple |
|
||||
|
||||
**Gap Analysis:**
|
||||
Authentication is implemented with three backends (local, LDAP/FreeIPA, OIDC/Keycloak) and a 3-tier role model (admin > editor > viewer). Audit logging captures user actions. Remaining gaps: group management, folder-level permissions, and state-based permission rules.
|
||||
|
||||
---
|
||||
|
||||
### 4. Search & Discovery
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Metadata search | Full with custom cards | Partial (API query params + fuzzy) | High | Moderate |
|
||||
| Full-text content search | iFilters for Office, CAD | None | Medium | Complex |
|
||||
| Quick search | Toolbar with history | Partial (fuzzy search API) | Medium | Simple |
|
||||
| Saved searches | User-defined favorites | None | Medium | Simple |
|
||||
| Advanced operators | AND, OR, NOT, wildcards | None | Medium | Simple |
|
||||
| Multi-variable search | Search across multiple fields | None | Medium | Simple |
|
||||
| Where-used search | Find all assemblies using part | Full | - | - |
|
||||
|
||||
**Gap Analysis:**
|
||||
Silo has API-level filtering, fuzzy search, and where-used queries. Remaining gaps: saved searches, advanced search operators, and a richer search UI. Content search (searching within CAD files) is not planned for the server.
|
||||
|
||||
---
|
||||
|
||||
### 5. BOM Management
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Single-level BOM | Yes | Full | - | - |
|
||||
| Multi-level BOM | Indented/exploded views | Full (recursive, configurable depth) | - | - |
|
||||
| BOM comparison | Between revisions | None | Medium | Moderate |
|
||||
| BOM export | Excel, XML, ERP formats | Full (CSV, ODS) | - | - |
|
||||
| BOM import | Bulk BOM loading | Full (CSV with upsert) | - | - |
|
||||
| Calculated BOMs | Quantities rolled up | None | Medium | Moderate |
|
||||
| Reference designators | Full support | Full | - | - |
|
||||
| Alternate parts | Substitute tracking | Full | - | - |
|
||||
|
||||
**Gap Analysis:**
|
||||
Multi-level BOM retrieval (recursive CTE with configurable depth) and BOM export (CSV, ODS) are implemented. BOM import supports CSV with upsert and cycle detection. Remaining gap: BOM comparison between revisions.
|
||||
|
||||
---
|
||||
|
||||
### 6. CAD Integration
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Native CAD add-in | Deep SOLIDWORKS integration | FreeCAD workbench (silo-mod) | Medium | Complex |
|
||||
| Property mapping | Bi-directional sync | Planned (silo-mod) | Medium | Moderate |
|
||||
| Task pane | Embedded in CAD UI | Auth dock panel (silo-mod) | Medium | Complex |
|
||||
| Lightweight components | Handle without full load | N/A | - | - |
|
||||
| Drawing/model linking | Automatic association | Manual | Medium | Moderate |
|
||||
| Multi-CAD support | Third-party formats | FreeCAD only | Low | - |
|
||||
|
||||
**Gap Analysis:**
|
||||
CAD integration is maintained in separate repositories ([silo-mod](https://git.kindred-systems.com/kindred/silo-mod), [silo-calc](https://git.kindred-systems.com/kindred/silo-calc)). The Silo server provides the REST API endpoints consumed by those clients.
|
||||
|
||||
---
|
||||
|
||||
### 7. External Integrations
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| ERP integration | SAP, Dynamics, etc. | Partial (Odoo stubs) | Medium | Complex |
|
||||
| API access | Full COM/REST API | Full REST API (78 endpoints) | - | - |
|
||||
| Dispatch scripts | Automation without coding | None | Medium | Moderate |
|
||||
| Task scheduler | Background processing | None | Medium | Moderate |
|
||||
| Email system | SMTP integration | None | High | Simple |
|
||||
| Web portal | Browser access | Full (React SPA + auth) | - | - |
|
||||
|
||||
**Gap Analysis:**
|
||||
Silo has a comprehensive REST API (78 endpoints) and a full web UI with authentication. Odoo ERP integration has config/sync-log scaffolding but push/pull operations are stubs. Remaining gaps: email notifications, task scheduler, dispatch automation.
|
||||
|
||||
---
|
||||
|
||||
### 8. Reporting & Analytics
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| Standard reports | Inventory, usage, activity | None | Medium | Moderate |
|
||||
| Custom reports | User-defined queries | None | Medium | Moderate |
|
||||
| Dashboard | Visual KPIs | None | Low | Moderate |
|
||||
| Export formats | PDF, Excel, CSV | CSV and ODS | Medium | Simple |
|
||||
|
||||
**Gap Analysis:**
|
||||
Reporting capabilities are absent. Basic reports (item counts, revision activity, where-used) would provide immediate value.
|
||||
|
||||
---
|
||||
|
||||
### 9. File Handling
|
||||
|
||||
| Feature | SOLIDWORKS PDM | Silo Status | Priority | Complexity |
|
||||
|---------|---------------|-------------|----------|------------|
|
||||
| File versioning | Automatic | Full (MinIO) | - | - |
|
||||
| File preview | Thumbnails, 3D preview | None | Medium | Complex |
|
||||
| File conversion | PDF, DXF generation | None | Medium | Complex |
|
||||
| Replication | Multi-site sync | None | Low | Complex |
|
||||
| File copy with refs | Copy tree with references | None | Medium | Moderate |
|
||||
|
||||
**Gap Analysis:**
|
||||
File storage works well. Thumbnail generation and file preview would significantly improve the web UI experience. Automatic conversion to PDF/DXF is valuable for sharing with non-CAD users.
|
||||
|
||||
---
|
||||
|
||||
### Gap Summary by Priority
|
||||
|
||||
#### Completed (Previously Critical/High)
|
||||
1. ~~**User authentication**~~ - Implemented: local, LDAP, OIDC
|
||||
2. ~~**Role-based permissions**~~ - Implemented: 3-tier role model (admin/editor/viewer)
|
||||
3. ~~**Audit trail**~~ - Implemented: audit_log table with completeness scoring
|
||||
4. ~~**Where-used search**~~ - Implemented: reverse parent lookup API
|
||||
5. ~~**Multi-level BOM API**~~ - Implemented: recursive expansion with configurable depth
|
||||
6. ~~**BOM export**~~ - Implemented: CSV and ODS formats
|
||||
|
||||
#### Critical Gaps (Required for Team Use)
|
||||
1. **Workflow engine** - State machines with transitions and approvals
|
||||
2. **Check-out locking** - Pessimistic locking for CAD files
|
||||
|
||||
#### High Priority Gaps (Significant Value)
|
||||
1. **Email notifications** - Alert users on state changes
|
||||
2. **Web UI search** - Advanced search interface with saved searches
|
||||
3. **Folder/state permissions** - Granular access control beyond role model
|
||||
|
||||
#### Medium Priority Gaps (Nice to Have)
|
||||
1. **Saved searches** - Frequently used queries
|
||||
2. **File preview/thumbnails** - Visual browsing
|
||||
3. **Reporting** - Activity and inventory reports
|
||||
4. **Scheduled tasks** - Background automation
|
||||
5. **BOM comparison** - Revision diff for assemblies
|
||||
|
||||
---
|
||||
|
||||
## Feature Roadmap
|
||||
|
||||
### Phase 1: Foundation (Current - Q2 2026)
|
||||
*Complete MVP and stabilize core functionality*
|
||||
|
||||
| Feature | Description | Status |
|
||||
|---------|-------------|--------|
|
||||
| MinIO integration | File upload/download with versioning and checksums | Complete |
|
||||
| Revision control | Rollback, comparison, status/labels | Complete |
|
||||
| CSV import/export | Dry-run validation, template generation | Complete |
|
||||
| ODS import/export | Items, BOMs, project sheets, templates | Complete |
|
||||
| Project management | CRUD, many-to-many item tagging | Complete |
|
||||
| Multi-level BOM | Recursive expansion, where-used, export | Complete |
|
||||
| Authentication | Local, LDAP, OIDC with role-based access | Complete |
|
||||
| Audit logging | Action logging, completeness scoring | Complete |
|
||||
| Unit tests | Core API and database operations | Not Started |
|
||||
| Date segment type | Support date-based part number segments | Not Started |
|
||||
| Part number validation | Validate format on creation | Not Started |
|
||||
| Location CRUD API | Expose location hierarchy via REST | Not Started |
|
||||
| Inventory API | Expose inventory operations via REST | Not Started |
|
||||
|
||||
### Phase 2: Multi-User (Q2-Q3 2026)
|
||||
*Enable team collaboration*
|
||||
|
||||
| Feature | Description | Status |
|
||||
|---------|-------------|--------|
|
||||
| LDAP authentication | Integrate with FreeIPA/Active Directory | **Complete** |
|
||||
| OIDC authentication | Keycloak / OpenID Connect | **Complete** |
|
||||
| Audit logging | Record all user actions with timestamps | **Complete** |
|
||||
| Session management | Token-based and session-based API authentication | **Complete** |
|
||||
| User/group management | Create, assign, manage users and groups | Not Started |
|
||||
| Folder permissions | Read/write/delete per folder hierarchy | Not Started |
|
||||
| Check-out locking | Pessimistic locks with timeout | Not Started |
|
||||
|
||||
### Phase 3: Workflow Engine (Q3-Q4 2026)
|
||||
*Implement engineering change processes*
|
||||
|
||||
| Feature | Description | Complexity |
|
||||
|---------|-------------|------------|
|
||||
| Workflow designer | YAML-defined state machines | Complex |
|
||||
| State transitions | Configurable transition rules | Complex |
|
||||
| Transition permissions | Who can execute which transitions | Moderate |
|
||||
| Single approvals | Basic approval workflow | Moderate |
|
||||
| Parallel approvals | Multi-approver gates | Complex |
|
||||
| Automatic transitions | Timer and condition-based | Complex |
|
||||
| Email notifications | SMTP integration for alerts | Simple |
|
||||
| Child state conditions | Block parent transitions | Moderate |
|
||||
|
||||
### Phase 4: Search & Discovery (Q4 2026 - Q1 2027)
|
||||
*Improve findability and navigation*
|
||||
|
||||
| Feature | Description | Status |
|
||||
|---------|-------------|--------|
|
||||
| Where-used queries | Find parent assemblies | **Complete** |
|
||||
| Fuzzy search | Quick search across items | **Complete** |
|
||||
| Advanced search UI | Web interface with filters | Not Started |
|
||||
| Search operators | AND, OR, NOT, wildcards | Not Started |
|
||||
| Saved searches | User favorites | Not Started |
|
||||
| Content search | Search within file content | Not Started |
|
||||
|
||||
### Phase 5: BOM & Reporting (Q1-Q2 2027)
|
||||
*Enhanced BOM management and analytics*
|
||||
|
||||
| Feature | Description | Status |
|
||||
|---------|-------------|--------|
|
||||
| Multi-level BOM API | Recursive assembly retrieval | **Complete** |
|
||||
| BOM export | CSV and ODS formats | **Complete** |
|
||||
| BOM import | CSV with upsert and cycle detection | **Complete** |
|
||||
| BOM comparison | Diff between revisions | Not Started |
|
||||
| Standard reports | Activity, inventory, usage | Not Started |
|
||||
| Custom queries | User-defined report builder | Not Started |
|
||||
| Dashboard | Visual KPIs and metrics | Not Started |
|
||||
|
||||
### Phase 6: Advanced Features (Q2-Q4 2027)
|
||||
*Enterprise capabilities*
|
||||
|
||||
| Feature | Description | Complexity |
|
||||
|---------|-------------|------------|
|
||||
| File preview | Thumbnail generation | Complex |
|
||||
| File conversion | Auto-generate PDF/DXF | Complex |
|
||||
| ERP integration | Adapter framework | Complex |
|
||||
| Task scheduler | Background job processing | Moderate |
|
||||
| Webhooks | Event notifications to external systems | Moderate |
|
||||
| API rate limiting | Protect against abuse | Simple |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1 Detailed Tasks
|
||||
|
||||
#### 1.1 MinIO Integration -- COMPLETE
|
||||
- [x] MinIO service configured in Docker Compose
|
||||
### 1.1 File Storage -- COMPLETE
|
||||
- [x] Filesystem storage backend
|
||||
- [x] File upload via REST API
|
||||
- [x] File download via REST API (latest and by revision)
|
||||
- [x] SHA256 checksums on upload
|
||||
|
||||
#### 1.2 Authentication & Authorization -- COMPLETE
|
||||
### 1.2 Authentication & Authorization -- COMPLETE
|
||||
- [x] Local authentication (bcrypt)
|
||||
- [x] LDAP/FreeIPA authentication
|
||||
- [x] OIDC/Keycloak authentication
|
||||
@@ -430,14 +393,14 @@ File storage works well. Thumbnail generation and file preview would significant
|
||||
- [x] CSRF protection (nosurf)
|
||||
- [x] Audit logging (database table)
|
||||
|
||||
#### 1.3 Multi-level BOM & Export -- COMPLETE
|
||||
### 1.3 Multi-level BOM & Export -- COMPLETE
|
||||
- [x] Recursive BOM expansion with configurable depth
|
||||
- [x] Where-used reverse lookup
|
||||
- [x] BOM CSV export/import with cycle detection
|
||||
- [x] BOM ODS export
|
||||
- [x] ODS item export/import/template
|
||||
|
||||
#### 1.4 Unit Test Suite
|
||||
### 1.4 Unit Test Suite
|
||||
- [ ] Database connection and transaction tests
|
||||
- [ ] Item CRUD operation tests
|
||||
- [ ] Revision creation and retrieval tests
|
||||
@@ -446,11 +409,11 @@ File storage works well. Thumbnail generation and file preview would significant
|
||||
- [ ] CSV import/export tests
|
||||
- [ ] API endpoint tests
|
||||
|
||||
#### 1.5 Missing Segment Types
|
||||
### 1.5 Missing Segment Types
|
||||
- [ ] Implement date segment type
|
||||
- [ ] Add strftime-style format support
|
||||
|
||||
#### 1.6 Location & Inventory APIs
|
||||
### 1.6 Location & Inventory APIs
|
||||
- [ ] `GET /api/locations` - List locations
|
||||
- [ ] `POST /api/locations` - Create location
|
||||
- [ ] `GET /api/locations/{path}` - Get location
|
||||
@@ -461,31 +424,7 @@ File storage works well. Thumbnail generation and file preview would significant
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Phase 1 (Foundation)
|
||||
- All existing tests pass
|
||||
- File upload/download works end-to-end
|
||||
- FreeCAD users can checkout, modify, commit parts
|
||||
|
||||
### Phase 2 (Multi-User)
|
||||
- 5+ concurrent users supported
|
||||
- No data corruption under concurrent access
|
||||
- Audit log captures all modifications
|
||||
|
||||
### Phase 3 (Workflow)
|
||||
- Engineering change process completable in Silo
|
||||
- Email notifications delivered reliably
|
||||
- Workflow state visible in web UI
|
||||
|
||||
### Phase 4+ (Advanced)
|
||||
- Search returns results in <2 seconds
|
||||
- Where-used queries complete in <5 seconds
|
||||
- BOM export matches assembly structure
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
## Appendix C: References
|
||||
|
||||
### SOLIDWORKS PDM Documentation
|
||||
- [SOLIDWORKS PDM Product Page](https://www.solidworks.com/product/solidworks-pdm)
|
||||
@@ -497,40 +436,7 @@ File storage works well. Thumbnail generation and file preview would significant
|
||||
- [SOLIDWORKS PDM API Getting Started](https://3dswym.3dexperience.3ds.com/wiki/solidworks-news-info/getting-started-with-the-solidworks-pdm-api-solidpractices_gBCYaM75RgORBcpSO1m_Mw)
|
||||
|
||||
### Silo Documentation
|
||||
- [Specification](docs/SPECIFICATION.md)
|
||||
- [Development Status](docs/STATUS.md)
|
||||
- [Deployment Guide](docs/DEPLOYMENT.md)
|
||||
- [Gap Analysis](docs/GAP_ANALYSIS.md)
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Feature Comparison Matrix
|
||||
|
||||
| Category | Feature | SW PDM Standard | SW PDM Pro | Silo Current | Silo Planned |
|
||||
|----------|---------|-----------------|------------|--------------|--------------|
|
||||
| **Version Control** | Check-in/out | Yes | Yes | No | Phase 2 |
|
||||
| | Version history | Yes | Yes | Yes | - |
|
||||
| | Rollback | Yes | Yes | Yes | - |
|
||||
| | Revision labels/status | Yes | Yes | Yes | - |
|
||||
| | Revision comparison | Yes | Yes | Yes (metadata) | - |
|
||||
| **Workflow** | Custom workflows | Limited | Yes | No | Phase 3 |
|
||||
| | Parallel approval | No | Yes | No | Phase 3 |
|
||||
| | Notifications | No | Yes | No | Phase 3 |
|
||||
| **Security** | User auth | Windows | Windows/LDAP | Yes (local, LDAP, OIDC) | - |
|
||||
| | Permissions | Basic | Granular | Partial (role-based) | Phase 2 |
|
||||
| | Audit trail | Basic | Full | Yes | - |
|
||||
| **Search** | Metadata search | Yes | Yes | Partial (API + fuzzy) | Phase 4 |
|
||||
| | Content search | No | Yes | No | Phase 4 |
|
||||
| | Where-used | Yes | Yes | Yes | - |
|
||||
| **BOM** | Single-level | Yes | Yes | Yes | - |
|
||||
| | Multi-level | Yes | Yes | Yes (recursive) | - |
|
||||
| | BOM export | Yes | Yes | Yes (CSV, ODS) | - |
|
||||
| **Data** | CSV import/export | Yes | Yes | Yes | - |
|
||||
| | ODS import/export | No | No | Yes | - |
|
||||
| | Project management | Yes | Yes | Yes | - |
|
||||
| **Integration** | API | Limited | Full | Full REST (75) | - |
|
||||
| | ERP connectors | No | Yes | Partial (Odoo stubs) | Phase 6 |
|
||||
| | Web access | No | Yes | Yes (React SPA + auth) | - |
|
||||
| **Files** | Versioning | Yes | Yes | Yes | - |
|
||||
| | Preview | Yes | Yes | No | Phase 6 |
|
||||
| | Multi-site | No | Yes | No | Not Planned |
|
||||
- [Specification](SPECIFICATION.md)
|
||||
- [Development Status](STATUS.md)
|
||||
- [Deployment Guide](DEPLOYMENT.md)
|
||||
- [Gap Analysis](GAP_ANALYSIS.md)
|
||||
|
||||
@@ -37,7 +37,7 @@ Silo treats **part numbering schemas as configuration, not code**. Multiple numb
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Silo Server (silod) │
|
||||
│ - REST API (78 endpoints) │
|
||||
│ - REST API (86 endpoints) │
|
||||
│ - Authentication (local, LDAP, OIDC) │
|
||||
│ - Schema parsing and validation │
|
||||
│ - Part number generation engine │
|
||||
@@ -49,9 +49,9 @@ Silo treats **part numbering schemas as configuration, not code**. Multiple numb
|
||||
┌───────────────┴───────────────┐
|
||||
▼ ▼
|
||||
┌─────────────────────────┐ ┌─────────────────────────────┐
|
||||
│ PostgreSQL │ │ MinIO │
|
||||
│ PostgreSQL │ │ Local Filesystem │
|
||||
│ (psql.example.internal)│ │ - File storage │
|
||||
│ - Item metadata │ │ - Versioned objects │
|
||||
│ - Item metadata │ │ - Revision files │
|
||||
│ - Relationships │ │ - Thumbnails │
|
||||
│ - Revision history │ │ │
|
||||
│ - Auth / Sessions │ │ │
|
||||
@@ -64,7 +64,7 @@ Silo treats **part numbering schemas as configuration, not code**. Multiple numb
|
||||
| Component | Technology | Notes |
|
||||
|-----------|------------|-------|
|
||||
| Database | PostgreSQL 16 | Existing instance at psql.example.internal |
|
||||
| File Storage | MinIO | S3-compatible, versioning enabled |
|
||||
| File Storage | Local filesystem | Files stored under configurable root directory |
|
||||
| CLI & API Server | Go (1.24) | chi/v5 router, pgx/v5 driver, zerolog |
|
||||
| Authentication | Multi-backend | Local (bcrypt), LDAP/FreeIPA, OIDC/Keycloak |
|
||||
| Sessions | PostgreSQL pgxstore | alexedwards/scs, 24h lifetime |
|
||||
@@ -83,7 +83,7 @@ An **item** is the fundamental entity. Items have:
|
||||
- **Properties** (key-value pairs, schema-defined and custom)
|
||||
- **Relationships** to other items
|
||||
- **Revisions** (append-only history)
|
||||
- **Files** (optional, stored in MinIO)
|
||||
- **Files** (optional, stored on the local filesystem)
|
||||
- **Location** (optional physical inventory location)
|
||||
|
||||
### 3.2 Database Schema (Conceptual)
|
||||
@@ -115,7 +115,7 @@ CREATE TABLE revisions (
|
||||
item_id UUID REFERENCES items(id) NOT NULL,
|
||||
revision_number INTEGER NOT NULL,
|
||||
properties JSONB NOT NULL, -- all properties at this revision
|
||||
file_version TEXT, -- MinIO version ID if applicable
|
||||
file_version TEXT, -- storage version ID if applicable
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
created_by TEXT, -- user identifier (future: LDAP DN)
|
||||
comment TEXT,
|
||||
@@ -345,7 +345,7 @@ CAD workbench and spreadsheet extension implementations are maintained in separa
|
||||
|
||||
### 5.1 File Storage Strategy
|
||||
|
||||
Files are stored as whole objects in MinIO with versioning enabled. Storage path convention: `items/{partNumber}/rev{N}.ext`. SHA-256 checksums are captured on upload for integrity verification.
|
||||
Files are stored on the local filesystem under a configurable root directory. Storage path convention: `items/{partNumber}/rev{N}.ext`. SHA-256 checksums are captured on upload for integrity verification.
|
||||
|
||||
Future option: exploded storage (unpack ZIP-based CAD archives for better diffing).
|
||||
|
||||
@@ -439,7 +439,7 @@ Revisions are created explicitly by user action (not automatic):
|
||||
### 7.3 Revision vs. File Version
|
||||
|
||||
- **Revision**: Silo metadata revision (tracked in PostgreSQL)
|
||||
- **File Version**: MinIO object version (automatic on upload)
|
||||
- **File Version**: File on disk corresponding to a revision
|
||||
|
||||
A single Silo revision may span multiple file uploads during editing. Only committed revisions create formal revision records.
|
||||
|
||||
@@ -598,12 +598,12 @@ See [AUTH.md](AUTH.md) for full architecture details and [AUTH_USER_GUIDE.md](AU
|
||||
|
||||
## 11. API Design
|
||||
|
||||
### 11.1 REST Endpoints (78 Implemented)
|
||||
### 11.1 REST Endpoints (86 Implemented)
|
||||
|
||||
```
|
||||
# Health (no auth)
|
||||
GET /health # Basic health check
|
||||
GET /ready # Readiness (DB + MinIO)
|
||||
GET /ready # Readiness (DB)
|
||||
|
||||
# Auth (no auth required)
|
||||
GET /login # Login page
|
||||
@@ -624,8 +624,8 @@ GET /api/auth/tokens # List user's API to
|
||||
POST /api/auth/tokens # Create API token
|
||||
DELETE /api/auth/tokens/{id} # Revoke API token
|
||||
|
||||
# Presigned Uploads (editor)
|
||||
POST /api/uploads/presign # Get presigned MinIO upload URL [editor]
|
||||
# Direct Uploads (editor)
|
||||
POST /api/uploads/presign # Get upload URL [editor]
|
||||
|
||||
# Schemas (read: viewer, write: editor)
|
||||
GET /api/schemas # List all schemas
|
||||
@@ -697,6 +697,20 @@ POST /api/items/{partNumber}/bom/merge # Merge BOM from ODS
|
||||
PUT /api/items/{partNumber}/bom/{childPartNumber} # Update BOM entry [editor]
|
||||
DELETE /api/items/{partNumber}/bom/{childPartNumber} # Remove BOM entry [editor]
|
||||
|
||||
# .kc Metadata (read: viewer, write: editor)
|
||||
GET /api/items/{partNumber}/metadata # Get indexed .kc metadata
|
||||
PUT /api/items/{partNumber}/metadata # Update metadata fields [editor]
|
||||
PATCH /api/items/{partNumber}/metadata/lifecycle # Transition lifecycle state [editor]
|
||||
PATCH /api/items/{partNumber}/metadata/tags # Add/remove tags [editor]
|
||||
|
||||
# .kc Dependencies (viewer)
|
||||
GET /api/items/{partNumber}/dependencies # List raw dependencies
|
||||
GET /api/items/{partNumber}/dependencies/resolve # Resolve UUIDs to part numbers + file availability
|
||||
|
||||
# .kc Macros (viewer)
|
||||
GET /api/items/{partNumber}/macros # List registered macros
|
||||
GET /api/items/{partNumber}/macros/{filename} # Get macro source content
|
||||
|
||||
# Audit (viewer)
|
||||
GET /api/audit/completeness # Item completeness scores
|
||||
GET /api/audit/completeness/{partNumber} # Item detail breakdown
|
||||
@@ -735,6 +749,139 @@ POST /api/inventory/{partNumber}/move
|
||||
|
||||
---
|
||||
|
||||
## 11.3 .kc File Integration
|
||||
|
||||
Silo supports the `.kc` file format — a ZIP archive that is a superset of FreeCAD's `.fcstd`. A `.kc` file contains everything an `.fcstd` does, plus a `silo/` directory with platform metadata.
|
||||
|
||||
#### Standard entries (preserved as-is)
|
||||
|
||||
`Document.xml`, `GuiDocument.xml`, BREP geometry files (`.brp`), `thumbnails/`
|
||||
|
||||
#### Silo entries (`silo/` directory)
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `silo/manifest.json` | Instance origin, part UUID, revision hash, `.kc` schema version |
|
||||
| `silo/metadata.json` | Custom schema field values, tags, lifecycle state |
|
||||
| `silo/history.json` | Local revision log (server-generated on checkout) |
|
||||
| `silo/dependencies.json` | Assembly link references by Silo UUID |
|
||||
| `silo/macros/*.py` | Embedded macro scripts bound to this part |
|
||||
|
||||
#### Commit-time extraction
|
||||
|
||||
When a `.kc` file is uploaded via `POST /api/items/{partNumber}/file`, the server:
|
||||
|
||||
1. Opens the ZIP and scans for `silo/` entries
|
||||
2. Parses `silo/manifest.json` and validates the UUID matches the item
|
||||
3. Upserts `silo/metadata.json` fields into the `item_metadata` table
|
||||
4. Replaces `silo/dependencies.json` entries in the `item_dependencies` table
|
||||
5. Replaces `silo/macros/*.py` entries in the `item_macros` table
|
||||
6. Broadcasts SSE events: `metadata.updated`, `dependencies.changed`, `macros.changed`
|
||||
|
||||
Extraction is best-effort — failures are logged as warnings but do not block the upload.
|
||||
|
||||
#### Checkout-time packing
|
||||
|
||||
When a `.kc` file is downloaded via `GET /api/items/{partNumber}/file/{revision}`, the server repacks the `silo/` directory with current database state:
|
||||
|
||||
- `silo/manifest.json` — current item UUID and metadata freshness
|
||||
- `silo/metadata.json` — latest schema fields, tags, lifecycle state
|
||||
- `silo/history.json` — last 20 revisions from the database
|
||||
- `silo/dependencies.json` — current dependency list from `item_dependencies`
|
||||
|
||||
Non-silo ZIP entries are passed through unchanged. If the file is a plain `.fcstd` (no `silo/` directory), it is served as-is.
|
||||
|
||||
ETag caching: the server computes an ETag from `revision_number:metadata.updated_at` and returns `304 Not Modified` when the client's `If-None-Match` header matches.
|
||||
|
||||
#### Lifecycle state machine
|
||||
|
||||
The `lifecycle_state` field in `item_metadata` follows this state machine:
|
||||
|
||||
```
|
||||
draft → review → released → obsolete
|
||||
↑ ↓
|
||||
└────────┘
|
||||
```
|
||||
|
||||
Valid transitions are enforced by `PATCH /metadata/lifecycle`. Invalid transitions return `422 Unprocessable Entity`.
|
||||
|
||||
#### Metadata response shape
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_name": "kindred-rd",
|
||||
"lifecycle_state": "draft",
|
||||
"tags": ["prototype", "v2"],
|
||||
"fields": {"material": "AL6061", "finish": "anodized"},
|
||||
"manifest": {
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"silo_instance": "silo.example.com",
|
||||
"revision_hash": "abc123",
|
||||
"kc_version": "1.0"
|
||||
},
|
||||
"updated_at": "2026-02-18T12:00:00Z",
|
||||
"updated_by": "forbes"
|
||||
}
|
||||
```
|
||||
|
||||
#### Dependency response shape
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"uuid": "550e8400-...",
|
||||
"part_number": "F01-0042",
|
||||
"revision": 3,
|
||||
"quantity": 4.0,
|
||||
"label": "M5 Bolt",
|
||||
"relationship": "component"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Resolved dependency response shape
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"uuid": "550e8400-...",
|
||||
"part_number": "F01-0042",
|
||||
"label": "M5 Bolt",
|
||||
"revision": 3,
|
||||
"quantity": 4.0,
|
||||
"resolved": true,
|
||||
"file_available": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Macro list response shape
|
||||
|
||||
```json
|
||||
[
|
||||
{"filename": "validate_dims.py", "trigger": "manual", "revision_number": 5}
|
||||
]
|
||||
```
|
||||
|
||||
#### Macro detail response shape
|
||||
|
||||
```json
|
||||
{
|
||||
"filename": "validate_dims.py",
|
||||
"trigger": "manual",
|
||||
"content": "import FreeCAD\n...",
|
||||
"revision_number": 5
|
||||
}
|
||||
```
|
||||
|
||||
#### Database tables (migration 018)
|
||||
|
||||
- `item_metadata` — schema fields, lifecycle state, tags, manifest info
|
||||
- `item_dependencies` — parent/child UUID references with quantity and relationship type
|
||||
- `item_macros` — filename, trigger type, source content, indexed per item
|
||||
|
||||
---
|
||||
|
||||
## 12. MVP Scope
|
||||
|
||||
### 12.1 Implemented
|
||||
@@ -743,8 +890,8 @@ POST /api/inventory/{partNumber}/move
|
||||
- [x] YAML schema parser for part numbering
|
||||
- [x] Part number generation engine
|
||||
- [x] CLI tool (`cmd/silo`)
|
||||
- [x] API server (`cmd/silod`) with 78 endpoints
|
||||
- [x] MinIO integration for file storage with versioning
|
||||
- [x] API server (`cmd/silod`) with 86 endpoints
|
||||
- [x] Filesystem-based file storage
|
||||
- [x] BOM relationships (component, alternate, reference)
|
||||
- [x] Multi-level BOM (recursive expansion with configurable depth)
|
||||
- [x] Where-used queries (reverse parent lookup)
|
||||
@@ -765,6 +912,12 @@ POST /api/inventory/{partNumber}/move
|
||||
- [x] Audit logging and completeness scoring
|
||||
- [x] CSRF protection (nosurf)
|
||||
- [x] Fuzzy search
|
||||
- [x] .kc file extraction pipeline (metadata, dependencies, macros indexed on commit)
|
||||
- [x] .kc file packing on checkout (manifest, metadata, history, dependencies)
|
||||
- [x] .kc metadata API (get, update fields, lifecycle transitions, tags)
|
||||
- [x] .kc dependency API (list, resolve with file availability)
|
||||
- [x] .kc macro API (list, get source content)
|
||||
- [x] ETag caching for .kc file downloads
|
||||
- [x] Property schema versioning framework
|
||||
- [x] Docker Compose deployment (dev and prod)
|
||||
- [x] systemd service and deployment scripts
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
| Component | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| PostgreSQL schema | Complete | 13 migrations applied |
|
||||
| PostgreSQL schema | Complete | 18 migrations applied |
|
||||
| YAML schema parser | Complete | Supports enum, serial, constant, string segments |
|
||||
| Part number generator | Complete | Scoped sequences, category-based format |
|
||||
| API server (`silod`) | Complete | 78 REST endpoints via chi/v5 |
|
||||
| API server (`silod`) | Complete | 86 REST endpoints via chi/v5 |
|
||||
| CLI tool (`silo`) | Complete | Item registration and management |
|
||||
| MinIO file storage | Complete | Upload, download, versioning, checksums |
|
||||
| Filesystem file storage | Complete | Upload, download, checksums |
|
||||
| Revision control | Complete | Append-only history, rollback, comparison, status/labels |
|
||||
| Project management | Complete | CRUD, many-to-many item tagging |
|
||||
| CSV import/export | Complete | Dry-run validation, template generation |
|
||||
@@ -29,7 +29,12 @@
|
||||
| CSRF protection | Complete | nosurf on web forms |
|
||||
| Fuzzy search | Complete | sahilm/fuzzy library |
|
||||
| Web UI | Complete | React SPA (Vite + TypeScript), 6 pages, Catppuccin Mocha theme |
|
||||
| File attachments | Complete | Presigned uploads, item file association, thumbnails |
|
||||
| File attachments | Complete | Direct uploads, item file association, thumbnails |
|
||||
| .kc extraction pipeline | Complete | Metadata, dependencies, macros indexed on commit |
|
||||
| .kc checkout packing | Complete | Manifest, metadata, history, dependencies repacked on download |
|
||||
| .kc metadata API | Complete | GET/PUT metadata, lifecycle transitions, tag management |
|
||||
| .kc dependency API | Complete | List raw deps, resolve UUIDs to part numbers + file availability |
|
||||
| .kc macro API | Complete | List macros, get source content by filename |
|
||||
| Odoo ERP integration | Partial | Config and sync-log CRUD functional; push/pull are stubs |
|
||||
| Docker Compose | Complete | Dev and production configurations |
|
||||
| Deployment scripts | Complete | setup-host, deploy, init-db, setup-ipa-nginx |
|
||||
@@ -56,7 +61,7 @@ FreeCAD workbench and LibreOffice Calc extension are maintained in separate repo
|
||||
| Service | Host | Status |
|
||||
|---------|------|--------|
|
||||
| PostgreSQL | psql.example.internal:5432 | Running |
|
||||
| MinIO | localhost:9000 (API) / :9001 (console) | Configured |
|
||||
| File Storage | /opt/silo/data (filesystem) | Configured |
|
||||
| Silo API | localhost:8080 | Builds successfully |
|
||||
|
||||
---
|
||||
@@ -96,3 +101,8 @@ The schema defines 170 category codes across 10 groups:
|
||||
| 011_item_files.sql | Item file attachments (item_files table, thumbnail_key column) |
|
||||
| 012_bom_source.sql | BOM entry source tracking |
|
||||
| 013_move_cost_sourcing_to_props.sql | Move sourcing_link and standard_cost from item columns to revision properties |
|
||||
| 014_settings.sql | Settings overrides and module state tables |
|
||||
| 015_jobs.sql | Job queue, runner, and job log tables |
|
||||
| 016_dag.sql | Dependency DAG nodes and edges |
|
||||
| 017_locations.sql | Location hierarchy and inventory tracking |
|
||||
| 018_kc_metadata.sql | .kc metadata tables (item_metadata, item_dependencies, item_macros, item_approvals, approval_signatures) |
|
||||
|
||||
515
docs/src/silo-server/STYLE.md
Normal file
@@ -0,0 +1,515 @@
|
||||
# Silo Style Guide
|
||||
|
||||
> Living reference for the Silo web UI. All modules must follow these conventions to maintain visual consistency across the platform.
|
||||
|
||||
---
|
||||
|
||||
## Color System
|
||||
|
||||
Silo uses the [Catppuccin Mocha](https://github.com/catppuccin/catppuccin) palette exclusively. All colors are referenced via CSS custom properties defined at `:root`.
|
||||
|
||||
### Palette
|
||||
|
||||
```
|
||||
--ctp-rosewater: #f5e0dc
|
||||
--ctp-flamingo: #f2cdcd
|
||||
--ctp-pink: #f5c2e7
|
||||
--ctp-mauve: #cba6f7
|
||||
--ctp-red: #f38ba8
|
||||
--ctp-maroon: #eba0ac
|
||||
--ctp-peach: #fab387
|
||||
--ctp-yellow: #f9e2af
|
||||
--ctp-green: #a6e3a1
|
||||
--ctp-teal: #94e2d5
|
||||
--ctp-sky: #89dceb
|
||||
--ctp-sapphire: #74c7ec
|
||||
--ctp-blue: #89b4fa
|
||||
--ctp-lavender: #b4befe
|
||||
--ctp-text: #cdd6f4
|
||||
--ctp-subtext1: #bac2de
|
||||
--ctp-subtext0: #a6adc8
|
||||
--ctp-overlay2: #9399b2
|
||||
--ctp-overlay1: #7f849c
|
||||
--ctp-overlay0: #6c7086
|
||||
--ctp-surface2: #585b70
|
||||
--ctp-surface1: #45475a
|
||||
--ctp-surface0: #313244
|
||||
--ctp-base: #1e1e2e
|
||||
--ctp-mantle: #181825
|
||||
--ctp-crust: #11111b
|
||||
```
|
||||
|
||||
### Semantic Roles
|
||||
|
||||
| Role | Token | Usage |
|
||||
|------|-------|-------|
|
||||
| Page background | `--ctp-base` | Main content area |
|
||||
| Panel background | `--ctp-mantle` | Sidebars, detail panes, headers |
|
||||
| Inset/input background | `--ctp-crust` | Form inputs, code blocks, drop zones |
|
||||
| Primary accent | `--ctp-mauve` | Primary buttons, active states, links, selection highlights |
|
||||
| Secondary accent | `--ctp-blue` | Informational highlights, secondary actions |
|
||||
| Success | `--ctp-green` | Confirmations, positive status |
|
||||
| Warning | `--ctp-yellow` | Caution states, pending actions |
|
||||
| Danger | `--ctp-red` | Destructive actions, errors, required indicators |
|
||||
| Informational | `--ctp-teal` | Auto-generated metadata, system-assigned values |
|
||||
| Body text | `--ctp-text` | Primary content |
|
||||
| Secondary text | `--ctp-subtext1` | Descriptions, timestamps |
|
||||
| Muted text | `--ctp-overlay1` | Placeholders, disabled states |
|
||||
| Borders | `--ctp-surface0` | Dividers, panel edges |
|
||||
| Hover borders | `--ctp-surface1` | Interactive element borders, row separators |
|
||||
| Focus ring | `rgba(203, 166, 247, 0.25)` | `box-shadow` on focused inputs (mauve at 25%) |
|
||||
|
||||
### Accent Usage for Data Types
|
||||
|
||||
| Data type | Color | Token |
|
||||
|-----------|-------|-------|
|
||||
| Assembly | `--ctp-mauve` | Badge, icon tint |
|
||||
| Part | `--ctp-green` | Badge, icon tint |
|
||||
| Document | `--ctp-blue` | Badge, icon tint |
|
||||
| Purchased | `--ctp-peach` | Badge, icon tint |
|
||||
| Phantom | `--ctp-overlay1` | Badge, icon tint |
|
||||
|
||||
These mappings are used anywhere item types appear: list badges, detail pane headers, BOM entries, tree views.
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
### Scale
|
||||
|
||||
| Role | Size | Weight | Token/Color | Transform |
|
||||
|------|------|--------|-------------|-----------|
|
||||
| Page title | 1.1rem | 600 | `--ctp-text` | None |
|
||||
| Section header | 11px | 600 | `--ctp-overlay0` | Uppercase, `letter-spacing: 0.06em` |
|
||||
| Form label | 11px | 600 | `--ctp-overlay1` | Uppercase, `letter-spacing: 0.05em` |
|
||||
| Body text | 13px | 400 | `--ctp-text` | None |
|
||||
| Table cell | 12px | 400 | `--ctp-text` | None |
|
||||
| Caption / metadata | 11px | 400 | `--ctp-subtext0` | None |
|
||||
| Badge text | 10px | 600 | Varies | Uppercase |
|
||||
| Breadcrumb segment | 13px | 500 | `--ctp-subtext1` | None |
|
||||
| Breadcrumb active | 13px | 600 | `--ctp-text` | None |
|
||||
|
||||
### Font Stack
|
||||
|
||||
```css
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
||||
```
|
||||
|
||||
No external font dependencies. System fonts ensure fast rendering and native feel across platforms.
|
||||
|
||||
### Rules
|
||||
|
||||
- Never use font sizes below 10px.
|
||||
- Use `font-weight: 600` for emphasis instead of bold (700). Reserve 700 for page titles only when extra weight is needed.
|
||||
- `text-transform: uppercase` is reserved for section headers, form labels, and badges. Never uppercase body text or descriptions.
|
||||
|
||||
---
|
||||
|
||||
## Spacing
|
||||
|
||||
Base unit: **4px**. All spacing values are multiples of 4.
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| `xs` | 4px (0.25rem) | Tight gaps: icon-to-label, tag internal padding |
|
||||
| `sm` | 8px (0.5rem) | Compact spacing: between related fields, badge padding |
|
||||
| `md` | 12px (0.75rem) | Standard: form group gaps, sidebar section padding |
|
||||
| `lg` | 16px (1rem) | Section separation, card padding |
|
||||
| `xl` | 24px (1.5rem) | Page-level padding, major section breaks |
|
||||
| `2xl` | 32px (2rem) | Page horizontal padding |
|
||||
|
||||
### Application
|
||||
|
||||
- **Page padding:** `1.5rem 2rem` (24px vertical, 32px horizontal)
|
||||
- **Sidebar section padding:** `1rem 1.25rem`
|
||||
- **Form grid gap:** `1.25rem 1.5rem` (row gap × column gap)
|
||||
- **Table row height:** 36px minimum (padding included)
|
||||
- **Table cell padding:** `0.4rem 0.75rem`
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
### Page Structure
|
||||
|
||||
Every module page follows the same shell:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Top Nav (52px) │
|
||||
├──────────┬──────────────────────────────────────┤
|
||||
│ App Menu │ Page Header (58px) │
|
||||
│ (icons) ├──────────────────────┬───────────────┤
|
||||
│ │ Content Area │ Detail Pane │
|
||||
│ │ │ (360px) │
|
||||
│ │ │ │
|
||||
│ │ │ │
|
||||
└──────────┴──────────────────────┴───────────────┘
|
||||
```
|
||||
|
||||
- **Top nav:** `52px` height, `--ctp-mantle` background, `1px solid --ctp-surface0` bottom border.
|
||||
- **App menu sidebar:** Icon strip on the left. Module icons, tooltips on hover. Active module highlighted with `--ctp-mauve` indicator.
|
||||
- **Page header:** `58px` height, `--ctp-mantle` background. Contains page title (with module icon), action buttons right-aligned.
|
||||
- **Content area:** `--ctp-base` background. Scrollable. Contains list views, kanban boards, or other primary content.
|
||||
- **Detail pane:** `360px` fixed width, `--ctp-mantle` background, `1px solid --ctp-surface0` left border. Appears on record selection.
|
||||
|
||||
### Grid Patterns
|
||||
|
||||
**Two-column form:**
|
||||
```css
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.25rem 1.5rem;
|
||||
max-width: 800px;
|
||||
```
|
||||
|
||||
**List + detail:**
|
||||
```css
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 360px;
|
||||
min-height: calc(100vh - 52px - 58px);
|
||||
```
|
||||
|
||||
### Breakpoints
|
||||
|
||||
Not currently required. Silo targets desktop browsers on engineering workstations. If mobile support is added later, breakpoints will be defined at `768px` and `1024px`.
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
### Buttons
|
||||
|
||||
Four tiers. All buttons share a base style:
|
||||
|
||||
```css
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.4rem 0.85rem;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
```
|
||||
|
||||
| Tier | Name | Background | Border | Text | Hover |
|
||||
|------|------|-----------|--------|------|-------|
|
||||
| Primary | `.btn-primary` | `--ctp-mauve` | `--ctp-mauve` | `--ctp-crust` | `--ctp-lavender` bg + border |
|
||||
| Secondary | `.btn` (default) | `--ctp-surface0` | `--ctp-surface1` | `--ctp-text` | `--ctp-surface1` bg, `--ctp-overlay0` border |
|
||||
| Ghost | `.btn-ghost` | transparent | transparent | `--ctp-subtext0` | `--ctp-surface0` bg, `--ctp-text` text |
|
||||
| Danger | `.btn-danger` | transparent | `--ctp-surface1` | `--ctp-red` | `rgba(243, 139, 168, 0.1)` bg, `--ctp-red` border |
|
||||
|
||||
Primary is used once per visible context (the main action). All other actions use secondary or ghost. Danger is only for destructive actions and always requires confirmation.
|
||||
|
||||
### Badges
|
||||
|
||||
Used for type indicators, status labels, and tags.
|
||||
|
||||
```css
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
```
|
||||
|
||||
Badges use a translucent background derived from their accent color:
|
||||
|
||||
```css
|
||||
/* Example: assembly badge */
|
||||
background: rgba(203, 166, 247, 0.15); /* --ctp-mauve at 15% */
|
||||
color: var(--ctp-mauve);
|
||||
```
|
||||
|
||||
Standard badge colors follow the [accent usage table](#accent-usage-for-data-types). Status badges:
|
||||
|
||||
| Status | Color |
|
||||
|--------|-------|
|
||||
| Active / Released | `--ctp-green` |
|
||||
| Draft / In Progress | `--ctp-blue` |
|
||||
| Review / Pending | `--ctp-yellow` |
|
||||
| Obsolete / Rejected | `--ctp-red` |
|
||||
| Locked | `--ctp-overlay1` |
|
||||
|
||||
### Form Inputs
|
||||
|
||||
All inputs share a base style:
|
||||
|
||||
```css
|
||||
background: var(--ctp-crust);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 6px;
|
||||
padding: 0.45rem 0.65rem;
|
||||
font-size: 12px;
|
||||
color: var(--ctp-text);
|
||||
transition: border-color 0.15s;
|
||||
```
|
||||
|
||||
| State | Border | Shadow |
|
||||
|-------|--------|--------|
|
||||
| Default | `--ctp-surface1` | None |
|
||||
| Hover | `--ctp-overlay0` | None |
|
||||
| Focus | `--ctp-mauve` | `0 0 0 0.2rem rgba(203, 166, 247, 0.25)` |
|
||||
| Error | `--ctp-red` | `0 0 0 0.2rem rgba(243, 139, 168, 0.15)` |
|
||||
| Disabled | `--ctp-surface0` | None, `opacity: 0.5` |
|
||||
|
||||
Placeholder text: `--ctp-overlay0`. Labels sit above inputs (never inline or floating).
|
||||
|
||||
### Tag Input
|
||||
|
||||
Used for multi-value fields (projects, tags):
|
||||
|
||||
```css
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
background: var(--ctp-crust);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 6px;
|
||||
min-height: 36px;
|
||||
```
|
||||
|
||||
Individual tags use the badge pattern: `rgba(accent, 0.15)` background with accent text. Remove button (×) at `opacity: 0.6`, `1.0` on hover.
|
||||
|
||||
### Tables
|
||||
|
||||
```css
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
```
|
||||
|
||||
| Element | Style |
|
||||
|---------|-------|
|
||||
| Header row | `background: --ctp-mantle`, `font-size: 11px`, uppercase, `--ctp-overlay1` text |
|
||||
| Body row | `border-bottom: 1px solid --ctp-surface0` |
|
||||
| Row hover | `background: --ctp-surface0` |
|
||||
| Row selected | `background: rgba(203, 166, 247, 0.08)` |
|
||||
| Cell padding | `0.4rem 0.75rem` |
|
||||
| Text columns | Left-aligned |
|
||||
| Number columns | Right-aligned |
|
||||
| Date columns | Right-aligned |
|
||||
| Action columns | Center-aligned |
|
||||
|
||||
Row actions use icon buttons (not text links). Icons at 14px, `--ctp-overlay1` default, `--ctp-text` on hover.
|
||||
|
||||
### Tabs
|
||||
|
||||
Used in detail panes and module sub-views:
|
||||
|
||||
```css
|
||||
display: flex;
|
||||
gap: 0;
|
||||
border-bottom: 2px solid var(--ctp-surface0);
|
||||
```
|
||||
|
||||
| State | Style |
|
||||
|-------|-------|
|
||||
| Default | `padding: 0.5rem 1rem`, `--ctp-subtext0` text, no border |
|
||||
| Hover | `--ctp-text` text |
|
||||
| Active | `--ctp-text` text, `font-weight: 600`, `border-bottom: 2px solid --ctp-mauve` (overlaps container border) |
|
||||
|
||||
### Section Dividers
|
||||
|
||||
Used to visually group form fields:
|
||||
|
||||
```css
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
grid-column: 1 / -1; /* span full form grid */
|
||||
margin-top: 0.75rem;
|
||||
```
|
||||
|
||||
Contains a label (`11px`, uppercase, `--ctp-overlay0`) and a horizontal line (`flex: 1`, `1px solid --ctp-surface0`).
|
||||
|
||||
### Sidebar Sections
|
||||
|
||||
Stacked vertically within detail panes:
|
||||
|
||||
```css
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid var(--ctp-surface0);
|
||||
```
|
||||
|
||||
Last section has no bottom border. Section titles follow the section header typography (11px, uppercase, `--ctp-overlay0`).
|
||||
|
||||
### Tooltips
|
||||
|
||||
Appear on hover after a 300ms delay. Position: above the target element by default, flip below if insufficient space.
|
||||
|
||||
```css
|
||||
background: var(--ctp-surface0);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 4px;
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 11px;
|
||||
color: var(--ctp-text);
|
||||
box-shadow: 0 4px 12px rgba(17, 17, 27, 0.4);
|
||||
```
|
||||
|
||||
### Breadcrumbs
|
||||
|
||||
Module navigation breadcrumbs:
|
||||
|
||||
```
|
||||
Module Name > List View > Record Name > Sub-view
|
||||
```
|
||||
|
||||
Separator: `>` character in `--ctp-overlay0`. Segments are clickable links in `--ctp-subtext1`. Active (final) segment is `--ctp-text` at `font-weight: 600`.
|
||||
|
||||
### Dropdowns / Selects
|
||||
|
||||
Follow the input base style. The dropdown menu:
|
||||
|
||||
```css
|
||||
background: var(--ctp-surface0);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 8px 24px rgba(17, 17, 27, 0.5);
|
||||
padding: 0.25rem;
|
||||
max-height: 240px;
|
||||
overflow-y: auto;
|
||||
```
|
||||
|
||||
Menu items:
|
||||
|
||||
```css
|
||||
padding: 0.4rem 0.65rem;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--ctp-text);
|
||||
cursor: pointer;
|
||||
```
|
||||
|
||||
Hover: `background: --ctp-surface1`. Selected: `background: rgba(203, 166, 247, 0.12)`, `color: --ctp-mauve`, `font-weight: 600`.
|
||||
|
||||
---
|
||||
|
||||
## Icons
|
||||
|
||||
Use [Lucide](https://lucide.dev) icons. Size: 14px for inline/table contexts, 16px for buttons and navigation, 20px for page headers and empty states.
|
||||
|
||||
Stroke width: 1.5px (Lucide default). Color inherits from parent text color unless explicitly set.
|
||||
|
||||
Do not mix icon libraries. If Lucide does not have a suitable icon, request one be added or create a custom SVG following Lucide's 24×24 grid and stroke conventions.
|
||||
|
||||
---
|
||||
|
||||
## Transitions & Animation
|
||||
|
||||
All interactive state changes use `transition: all 0.15s ease`. This applies to hover, focus, active, and open/close states.
|
||||
|
||||
No entrance animations on page load. Content renders immediately. Skeleton loaders are acceptable for async data using a pulsing `--ctp-surface0` → `--ctp-surface1` gradient.
|
||||
|
||||
Dropdown menus and tooltips appear instantly (no slide/fade). Collapse/expand panels (if used) transition `max-height` at `0.2s ease`.
|
||||
|
||||
---
|
||||
|
||||
## Styling Implementation
|
||||
|
||||
Silo's React frontend uses **inline `React.CSSProperties` objects** with `var(--ctp-*)` token references. This is the project convention and must not be changed.
|
||||
|
||||
### Rules
|
||||
|
||||
- No CSS modules, no Tailwind, no external CSS-in-JS libraries.
|
||||
- Styles are defined as `const` objects at the top of each component file.
|
||||
- Shared style patterns (button base, input base) can be extracted to a `styles/` directory as exported `CSSProperties` objects.
|
||||
- Use `as const` or `as React.CSSProperties` for type safety.
|
||||
- Pseudo-classes (`:hover`, `:focus`) require state-driven inline styles or a thin CSS file for the base pseudo-class rules.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
const styles = {
|
||||
container: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 360px',
|
||||
height: '100%',
|
||||
overflow: 'hidden',
|
||||
} as React.CSSProperties,
|
||||
|
||||
sidebar: {
|
||||
background: 'var(--ctp-mantle)',
|
||||
borderLeft: '1px solid var(--ctp-surface0)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
overflowY: 'auto' as const,
|
||||
} as React.CSSProperties,
|
||||
};
|
||||
```
|
||||
|
||||
### Pseudo-class CSS
|
||||
|
||||
A single `silo-base.css` file provides pseudo-class rules that cannot be expressed inline:
|
||||
|
||||
```css
|
||||
/* Hover, focus, and active states for core interactive elements */
|
||||
.silo-input:hover { border-color: var(--ctp-overlay0); }
|
||||
.silo-input:focus { border-color: var(--ctp-mauve); box-shadow: 0 0 0 0.2rem rgba(203, 166, 247, 0.25); }
|
||||
.silo-btn:hover { /* per-tier overrides */ }
|
||||
.silo-row:hover { background: var(--ctp-surface0); }
|
||||
```
|
||||
|
||||
Components apply the corresponding class names alongside their inline styles. This is the only place class-based styling is used.
|
||||
|
||||
---
|
||||
|
||||
## Do / Don't
|
||||
|
||||
| Do | Don't |
|
||||
|----|-------|
|
||||
| Use `var(--ctp-*)` for every color | Hardcode hex values |
|
||||
| Use the 4px spacing scale | Use arbitrary padding/margins |
|
||||
| Use Lucide icons at standard sizes | Mix icon libraries |
|
||||
| Use inline `CSSProperties` | Use CSS modules or Tailwind |
|
||||
| One primary button per visible context | Multiple competing primary buttons |
|
||||
| Use translucent accent backgrounds for badges | Use solid bright backgrounds for badges |
|
||||
| Use icon buttons for row-level table actions | Use text links in table rows |
|
||||
| Define styles as `const` at file top | Inline style objects in JSX |
|
||||
| Show tooltips on icon-only buttons | Leave icon buttons unlabeled |
|
||||
| Use section dividers to group form fields | Use cards or borders around field groups |
|
||||
| Follow the breadcrumb pattern for navigation | Use nested tab bars |
|
||||
|
||||
---
|
||||
|
||||
## Appendix: CSS Custom Properties Block
|
||||
|
||||
Paste this at the root of the application stylesheet:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--ctp-rosewater: #f5e0dc;
|
||||
--ctp-flamingo: #f2cdcd;
|
||||
--ctp-pink: #f5c2e7;
|
||||
--ctp-mauve: #cba6f7;
|
||||
--ctp-red: #f38ba8;
|
||||
--ctp-maroon: #eba0ac;
|
||||
--ctp-peach: #fab387;
|
||||
--ctp-yellow: #f9e2af;
|
||||
--ctp-green: #a6e3a1;
|
||||
--ctp-teal: #94e2d5;
|
||||
--ctp-sky: #89dceb;
|
||||
--ctp-sapphire: #74c7ec;
|
||||
--ctp-blue: #89b4fa;
|
||||
--ctp-lavender: #b4befe;
|
||||
--ctp-text: #cdd6f4;
|
||||
--ctp-subtext1: #bac2de;
|
||||
--ctp-subtext0: #a6adc8;
|
||||
--ctp-overlay2: #9399b2;
|
||||
--ctp-overlay1: #7f849c;
|
||||
--ctp-overlay0: #6c7086;
|
||||
--ctp-surface2: #585b70;
|
||||
--ctp-surface1: #45475a;
|
||||
--ctp-surface0: #313244;
|
||||
--ctp-base: #1e1e2e;
|
||||
--ctp-mantle: #181825;
|
||||
--ctp-crust: #11111b;
|
||||
}
|
||||
```
|
||||
364
docs/src/silo-server/WORKERS.md
Normal file
@@ -0,0 +1,364 @@
|
||||
# Worker System Specification
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
The worker system provides async compute job execution for Silo. Jobs are defined as YAML files, managed by the Silo server, and executed by external runner processes. The system is general-purpose -- while DAG validation is the first use case, it supports any compute workload: geometry export, thumbnail rendering, FEA/CFD batch jobs, report generation, and data migration.
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture
|
||||
|
||||
```
|
||||
YAML Job Definitions (files on disk, version-controllable)
|
||||
|
|
||||
v
|
||||
Silo Server (parser, scheduler, state machine, REST API, SSE events)
|
||||
|
|
||||
v
|
||||
Runners (silorunner binary, polls via REST, executes Headless Create)
|
||||
```
|
||||
|
||||
**Three layers:**
|
||||
|
||||
1. **Job definitions** -- YAML files in a configurable directory (default `/etc/silo/jobdefs`). Each file defines a job type: what triggers it, what it operates on, what computation to perform, and what runner capabilities are required. These are the source of truth and can be version-controlled alongside other Silo config.
|
||||
|
||||
2. **Silo server** -- Parses YAML definitions on startup and upserts them into the `job_definitions` table. Creates job instances when triggers fire (revision created, BOM changed, manual). Manages job lifecycle, enforces timeouts, and broadcasts status via SSE.
|
||||
|
||||
3. **Runners** -- Separate `silorunner` processes that authenticate with Silo via API tokens, poll for available jobs, claim them atomically, execute the compute, and report results. A runner host must have Headless Create and silo-mod installed for geometry jobs.
|
||||
|
||||
---
|
||||
|
||||
## 3. Job Definition Format
|
||||
|
||||
Job definitions are YAML files with the following structure:
|
||||
|
||||
```yaml
|
||||
job:
|
||||
name: assembly-validate
|
||||
version: 1
|
||||
description: "Validate assembly by rebuilding its dependency subgraph"
|
||||
|
||||
trigger:
|
||||
type: revision_created # revision_created, bom_changed, manual, schedule
|
||||
filter:
|
||||
item_type: assembly # only trigger for assemblies
|
||||
|
||||
scope:
|
||||
type: assembly # item, assembly, project
|
||||
|
||||
compute:
|
||||
type: validate # validate, rebuild, diff, export, custom
|
||||
command: create-validate # runner-side command identifier
|
||||
args: # passed to runner as JSON
|
||||
rebuild_mode: incremental
|
||||
check_interference: true
|
||||
|
||||
runner:
|
||||
tags: [create] # required runner capabilities
|
||||
|
||||
timeout: 900 # seconds before job is marked failed (default 600)
|
||||
max_retries: 2 # retry count on failure (default 1)
|
||||
priority: 50 # lower = higher priority (default 100)
|
||||
```
|
||||
|
||||
### 3.1 Trigger Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `revision_created` | Fires when a new revision is created on an item matching the filter |
|
||||
| `bom_changed` | Fires when a BOM merge completes |
|
||||
| `manual` | Only triggered via `POST /api/jobs` |
|
||||
| `schedule` | Future: cron-like scheduling (not yet implemented) |
|
||||
|
||||
### 3.2 Trigger Filters
|
||||
|
||||
The `filter` map supports key-value matching against item properties:
|
||||
|
||||
| Key | Description |
|
||||
|-----|-------------|
|
||||
| `item_type` | Match item type: `part`, `assembly`, `drawing`, etc. |
|
||||
| `schema` | Match schema name |
|
||||
|
||||
All filter keys must match for the trigger to fire. An empty filter matches all items.
|
||||
|
||||
### 3.3 Scope Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `item` | Job operates on a single item |
|
||||
| `assembly` | Job operates on an assembly and its BOM tree |
|
||||
| `project` | Job operates on all items in a project |
|
||||
|
||||
### 3.4 Compute Commands
|
||||
|
||||
The `command` field identifies what the runner should execute. Built-in commands:
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `create-validate` | Open file in Headless Create, rebuild features, report validation results |
|
||||
| `create-export` | Open file, export to specified format (STEP, IGES, 3MF) |
|
||||
| `create-dag-extract` | Open file, extract feature DAG, output as JSON |
|
||||
| `create-thumbnail` | Open file, render thumbnail image |
|
||||
|
||||
Custom commands can be added by extending silo-mod's `silo.runner` module.
|
||||
|
||||
---
|
||||
|
||||
## 4. Job Lifecycle
|
||||
|
||||
```
|
||||
pending → claimed → running → completed
|
||||
→ failed
|
||||
→ cancelled
|
||||
```
|
||||
|
||||
| State | Description |
|
||||
|-------|-------------|
|
||||
| `pending` | Job created, waiting for a runner to claim it |
|
||||
| `claimed` | Runner has claimed the job. `expires_at` is set. |
|
||||
| `running` | Runner has started execution (reported via progress update) |
|
||||
| `completed` | Runner reported success. `result` JSONB contains output. |
|
||||
| `failed` | Runner reported failure, timeout expired, or max retries exceeded |
|
||||
| `cancelled` | Admin cancelled the job before completion |
|
||||
|
||||
### 4.1 Claim Semantics
|
||||
|
||||
Runners claim jobs via `POST /api/runner/claim`. The server uses PostgreSQL's `SELECT FOR UPDATE SKIP LOCKED` to ensure exactly-once delivery:
|
||||
|
||||
```sql
|
||||
WITH claimable AS (
|
||||
SELECT id FROM jobs
|
||||
WHERE status = 'pending'
|
||||
AND runner_tags <@ $2::text[]
|
||||
ORDER BY priority ASC, created_at ASC
|
||||
LIMIT 1
|
||||
FOR UPDATE SKIP LOCKED
|
||||
)
|
||||
UPDATE jobs SET
|
||||
status = 'claimed',
|
||||
runner_id = $1,
|
||||
claimed_at = now(),
|
||||
expires_at = now() + (timeout_seconds || ' seconds')::interval
|
||||
FROM claimable
|
||||
WHERE jobs.id = claimable.id
|
||||
RETURNING jobs.*;
|
||||
```
|
||||
|
||||
The `runner_tags <@ $2::text[]` condition ensures the runner has all tags required by the job. A runner with tags `["create", "linux", "gpu"]` can claim a job requiring `["create"]`, but not one requiring `["create", "windows"]`.
|
||||
|
||||
### 4.2 Timeout Enforcement
|
||||
|
||||
A background sweeper runs every 30 seconds (configurable via `jobs.job_timeout_check`) and marks expired jobs as failed:
|
||||
|
||||
```sql
|
||||
UPDATE jobs SET status = 'failed', error_message = 'job timed out'
|
||||
WHERE status IN ('claimed', 'running')
|
||||
AND expires_at < now();
|
||||
```
|
||||
|
||||
### 4.3 Retry
|
||||
|
||||
When a job fails and `retry_count < max_retries`, a new job is created with the same definition and scope, with `retry_count` incremented.
|
||||
|
||||
---
|
||||
|
||||
## 5. Runners
|
||||
|
||||
### 5.1 Registration
|
||||
|
||||
Runners are registered via `POST /api/runners` (admin only). The server generates a token (shown once) and stores the SHA-256 hash in the `runners` table. This follows the same pattern as API tokens in `internal/auth/token.go`.
|
||||
|
||||
### 5.2 Authentication
|
||||
|
||||
Runners authenticate via `Authorization: Bearer silo_runner_<token>`. A dedicated `RequireRunnerAuth` middleware validates the token against the `runners` table and injects a `RunnerIdentity` into the request context.
|
||||
|
||||
### 5.3 Heartbeat
|
||||
|
||||
Runners send `POST /api/runner/heartbeat` every 30 seconds. The server updates `last_heartbeat` and sets `status = 'online'`. A background sweeper marks runners as `offline` if their heartbeat is older than `runner_timeout` seconds (default 90).
|
||||
|
||||
### 5.4 Tags
|
||||
|
||||
Each runner declares capability tags (e.g., `["create", "linux", "gpu"]`). Jobs require specific tags via the `runner.tags` field in their YAML definition. A runner can only claim jobs whose required tags are a subset of the runner's tags.
|
||||
|
||||
### 5.5 Runner Config
|
||||
|
||||
The `silorunner` binary reads its config from a YAML file:
|
||||
|
||||
```yaml
|
||||
server_url: "https://silo.example.com"
|
||||
token: "silo_runner_abc123..."
|
||||
name: "worker-01"
|
||||
tags: ["create", "linux"]
|
||||
poll_interval: 5 # seconds between claim attempts
|
||||
create_path: "/usr/bin/create" # path to Headless Create binary (with silo-mod installed)
|
||||
```
|
||||
|
||||
Or via environment variables: `SILO_RUNNER_SERVER_URL`, `SILO_RUNNER_TOKEN`, etc.
|
||||
|
||||
### 5.6 Deployment
|
||||
|
||||
Runner prerequisites:
|
||||
- `silorunner` binary (built from `cmd/silorunner/`)
|
||||
- Headless Create (Kindred's fork of FreeCAD) with silo-mod workbench installed
|
||||
- Network access to Silo server API
|
||||
|
||||
Runners can be deployed as:
|
||||
- Bare metal processes alongside Create installations
|
||||
- Docker containers with Create pre-installed
|
||||
- Scaled horizontally by registering multiple runners with different names
|
||||
|
||||
---
|
||||
|
||||
## 6. Job Log
|
||||
|
||||
Each job has an append-only log stored in the `job_log` table. Runners append entries via `POST /api/runner/jobs/{jobID}/log`:
|
||||
|
||||
```json
|
||||
{
|
||||
"level": "info",
|
||||
"message": "Rebuilding Pad003...",
|
||||
"metadata": {"node_key": "Pad003", "progress_pct": 45}
|
||||
}
|
||||
```
|
||||
|
||||
Log levels: `debug`, `info`, `warn`, `error`.
|
||||
|
||||
---
|
||||
|
||||
## 7. SSE Events
|
||||
|
||||
All job lifecycle transitions are broadcast via Silo's SSE broker. Clients subscribe to `/api/events` and receive:
|
||||
|
||||
| Event Type | Payload | When |
|
||||
|------------|---------|------|
|
||||
| `job.created` | `{id, definition_name, item_id, status, priority}` | Job created |
|
||||
| `job.claimed` | `{id, runner_id, runner_name}` | Runner claims job |
|
||||
| `job.progress` | `{id, progress, progress_message}` | Runner reports progress (0-100) |
|
||||
| `job.completed` | `{id, result_summary, duration_seconds}` | Job completed successfully |
|
||||
| `job.failed` | `{id, error_message}` | Job failed |
|
||||
| `job.cancelled` | `{id, cancelled_by}` | Admin cancelled job |
|
||||
| `runner.online` | `{id, name, tags}` | Runner heartbeat (first after offline) |
|
||||
| `runner.offline` | `{id, name}` | Runner heartbeat timeout |
|
||||
|
||||
---
|
||||
|
||||
## 8. REST API
|
||||
|
||||
### 8.1 Job Endpoints (user-facing, require auth)
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/jobs` | viewer | List jobs (filterable by status, item, definition) |
|
||||
| `GET` | `/api/jobs/{jobID}` | viewer | Get job details |
|
||||
| `GET` | `/api/jobs/{jobID}/logs` | viewer | Get job log entries |
|
||||
| `POST` | `/api/jobs` | editor | Manually trigger a job |
|
||||
| `POST` | `/api/jobs/{jobID}/cancel` | editor | Cancel a pending/running job |
|
||||
|
||||
### 8.2 Job Definition Endpoints
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/job-definitions` | viewer | List loaded definitions |
|
||||
| `GET` | `/api/job-definitions/{name}` | viewer | Get specific definition |
|
||||
| `POST` | `/api/job-definitions/reload` | admin | Re-read YAML from disk |
|
||||
|
||||
### 8.3 Runner Management Endpoints (admin)
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/runners` | admin | List registered runners |
|
||||
| `POST` | `/api/runners` | admin | Register runner (returns token) |
|
||||
| `DELETE` | `/api/runners/{runnerID}` | admin | Delete runner |
|
||||
|
||||
### 8.4 Runner-Facing Endpoints (runner token auth)
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `POST` | `/api/runner/heartbeat` | runner | Send heartbeat |
|
||||
| `POST` | `/api/runner/claim` | runner | Claim next available job |
|
||||
| `PUT` | `/api/runner/jobs/{jobID}/progress` | runner | Report progress |
|
||||
| `POST` | `/api/runner/jobs/{jobID}/complete` | runner | Report completion with result |
|
||||
| `POST` | `/api/runner/jobs/{jobID}/fail` | runner | Report failure |
|
||||
| `POST` | `/api/runner/jobs/{jobID}/log` | runner | Append log entry |
|
||||
| `PUT` | `/api/runner/jobs/{jobID}/dag` | runner | Sync DAG results after compute |
|
||||
|
||||
---
|
||||
|
||||
## 9. Configuration
|
||||
|
||||
Add to `config.yaml`:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
directory: /etc/silo/jobdefs # path to YAML job definitions
|
||||
runner_timeout: 90 # seconds before marking runner offline
|
||||
job_timeout_check: 30 # seconds between timeout sweeps
|
||||
default_priority: 100 # default job priority
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Example Job Definitions
|
||||
|
||||
### Assembly Validation
|
||||
|
||||
```yaml
|
||||
job:
|
||||
name: assembly-validate
|
||||
version: 1
|
||||
description: "Validate assembly by rebuilding its dependency subgraph"
|
||||
trigger:
|
||||
type: revision_created
|
||||
filter:
|
||||
item_type: assembly
|
||||
scope:
|
||||
type: assembly
|
||||
compute:
|
||||
type: validate
|
||||
command: create-validate
|
||||
args:
|
||||
rebuild_mode: incremental
|
||||
check_interference: true
|
||||
runner:
|
||||
tags: [create]
|
||||
timeout: 900
|
||||
max_retries: 2
|
||||
priority: 50
|
||||
```
|
||||
|
||||
### STEP Export
|
||||
|
||||
```yaml
|
||||
job:
|
||||
name: part-export-step
|
||||
version: 1
|
||||
description: "Export a part to STEP format"
|
||||
trigger:
|
||||
type: manual
|
||||
scope:
|
||||
type: item
|
||||
compute:
|
||||
type: export
|
||||
command: create-export
|
||||
args:
|
||||
format: step
|
||||
output_key_template: "exports/{part_number}_rev{revision}.step"
|
||||
runner:
|
||||
tags: [create]
|
||||
timeout: 300
|
||||
max_retries: 1
|
||||
priority: 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. References
|
||||
|
||||
- [DAG.md](DAG.md) -- Dependency DAG specification
|
||||
- [MULTI_USER_EDITS.md](MULTI_USER_EDITS.md) -- Multi-user editing specification
|
||||
- [ROADMAP.md](ROADMAP.md) -- Tier 0 Job Queue Infrastructure, Tier 1 Headless Create
|
||||
@@ -118,7 +118,7 @@ The server provides the REST API and ODS endpoints consumed by these clients.
|
||||
| [docs/AUTH_USER_GUIDE.md](docs/AUTH_USER_GUIDE.md) | User guide for login, tokens, and roles |
|
||||
| [docs/GAP_ANALYSIS.md](docs/GAP_ANALYSIS.md) | Gap analysis and revision control roadmap |
|
||||
| [docs/COMPONENT_AUDIT.md](docs/COMPONENT_AUDIT.md) | Component audit tool design |
|
||||
| [ROADMAP.md](ROADMAP.md) | Feature roadmap and SOLIDWORKS PDM comparison |
|
||||
| [docs/ROADMAP.md](docs/ROADMAP.md) | Platform roadmap, dependency tiers, and gap summary |
|
||||
| [frontend-spec.md](frontend-spec.md) | React SPA frontend specification |
|
||||
|
||||
## License
|
||||
|
||||
43
icons/mappings/FCAD.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
#fce94f,#edd400,#c4a000,#302b00
|
||||
#8ae234,#73d216,#4e9a06,#172a04
|
||||
#fcaf3e,#f57900,#ce5c00,#321900
|
||||
#729fcf,#3465a4,#204a87,#0b1521
|
||||
#ad7fa8,#75507b,#5c3566,#171018
|
||||
#e9b96e,#c17d11,#8f5902,#271903
|
||||
#ef2929,#cc0000,#a40000,#280000
|
||||
#34e0e2,#16d0d2,#06989a,#042a2a
|
||||
#ffffff,#eeeeec,#d3d7cf,#babdb6
|
||||
#888a85,#555753,#2e3436,#000000
|
||||
#faff2b,#fff520,#fff110,#fff300
|
||||
#ffe83f,#ffe100,#ffed00,#ffff00
|
||||
#fcc217,#fdb616,#ffaa00,#ffa200
|
||||
#c89600,#aa6c00,#af7d00,#a7873d
|
||||
#cabd55,#e3d032,#c9830a,#231f0b
|
||||
#2b2200
|
||||
#ff5f00,#ff6200,#cf7008
|
||||
#ff0000,#ff2600,#ef3535,#ff4c4c
|
||||
#c91a1a,#d40000,#c51900,#a70202
|
||||
#3d0000,#230b0b,#2e0000
|
||||
#6dff00,#00ff00,#52ff00,#00fd00
|
||||
#31d900,#00b800,#4bff54
|
||||
#2e8207,#0f7d0f,#17230b,#162c02
|
||||
#71b2f8,#89d5f8,#639ef0,#83a8d8
|
||||
#c8e0f9,#c1e3f7,#c4d7eb,#b9cfe7
|
||||
#379cfb,#89aedc,#528ac5,#5b86be
|
||||
#637dca,#3977c3,#1e64ff
|
||||
#0000ff,#0069ff,#0090ff,#0040ff
|
||||
#0087ff,#0046ff,#005bff,#0066ff
|
||||
#061aff,#3f3fff,#0061e6,#0099e5
|
||||
#003ddd,#001ccc,#0619c0
|
||||
#0019a3,#002795
|
||||
#0c1522,#0f222f
|
||||
#00e5ff,#01d6d6,#00899e,#0b1e23
|
||||
#fafafa,#f8f8f8,#f7f7f7,#fafbf9
|
||||
#f0f0f0,#f0f1f1,#eeeeee,#ededed
|
||||
#e8e8e8,#e5e5e5,#e2e2e2
|
||||
#dcdcdc,#d8d8d8,#d6d6d6,#d1d1d1
|
||||
#cccccc,#c8c8c8,#ccd0c7,#bbbbbb
|
||||
#b8b8b8,#a3a3a3,#9a9a9a,#999999
|
||||
#897e7e,#666666,#5f5f5f
|
||||
#505050,#4c4c4c,#403c3d,#3f3f3f
|
||||
#e5007e,#bf3995,#260013
|
||||
|
43
icons/mappings/kindred.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
#f9e2af,#f8c459,#bc8009,#664506
|
||||
#a6e3a1,#6cd163,#359b2e,#1c5017
|
||||
#fab387,#f77e33,#b44908,#6e2d04
|
||||
#89b4fa,#307bf7,#0846b3,#052459
|
||||
#cba6f7,#8a39ec,#5710ad,#290850
|
||||
#f5c2e7,#e86ec6,#b11b87,#490b38
|
||||
#f2cdcd,#d76363,#912424,#4c1313
|
||||
#94e2d5,#54d1bc,#258e7e,#103b35
|
||||
#cdd6f4,#7f849c,#6c7086,#585b70
|
||||
#45475a,#313244,#1e1e2e,#11111b
|
||||
#f9d791,#f9d487,#f8cf78,#f8ca69
|
||||
#f9dea3,#f8ca69,#f8ca69,#f8ca69
|
||||
#f8d07c,#f8d07c,#f8ca69,#f8ca69
|
||||
#c28711,#ad7608,#b07809,#ebb547
|
||||
#f9d487,#f8d17e,#d29926,#664506
|
||||
#664506
|
||||
#f7863f,#f7863f,#c35512
|
||||
#e9aaaa,#e9aaaa,#f2cdcd,#f2cdcd
|
||||
#df8383,#da6e6e,#cb5858,#9a2c2c
|
||||
#581616,#4f1414,#4f1414
|
||||
#89da82,#89da82,#89da82,#86d97f
|
||||
#61c658,#47ad40,#a6e3a1
|
||||
#308c29,#318e2a,#1c5017,#1c5017
|
||||
#89b4fa,#89b4fa,#89b4fa,#89b4fa
|
||||
#89b4fa,#89b4fa,#89b4fa,#89b4fa
|
||||
#7cacfa,#89b4fa,#659df9,#679ef9
|
||||
#78a9f9,#4f8ff8,#6aa0f9
|
||||
#5190f8,#5190f8,#5190f8,#5190f8
|
||||
#5190f8,#5190f8,#5190f8,#5190f8
|
||||
#5693f8,#86b2fa,#3c83f7,#3b82f7
|
||||
#347ef7,#266ee6,#2168de
|
||||
#0845b0,#0841a6
|
||||
#05255a,#052966
|
||||
#74dac8,#49c1ad,#258d7d,#103b35
|
||||
#b7bfdc,#afb6d2,#aab2cd,#b7bfdc
|
||||
#8c92ab,#8e94ad,#8389a1,#7f849c
|
||||
#7b8098,#797e95,#777c93
|
||||
#73778e,#70748a,#6e7289,#6a6e84
|
||||
#676a80,#63677d,#676a80,#595c71
|
||||
#585b70,#585b70,#585b70,#585b70
|
||||
#434558,#38394b,#353648
|
||||
#2e2f41,#2c2d3e,#252536,#252536
|
||||
#9b56ef,#a86cf1,#290850
|
||||
|
209
icons/retheme.py
Normal file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Retheme FreeCAD SVG icons by replacing color palettes.
|
||||
|
||||
Reads two CSV files with matching rows (source and target palettes),
|
||||
builds a color mapping, and applies it to all SVG files found in the
|
||||
input directories.
|
||||
|
||||
Usage:
|
||||
python icons/retheme.py [options]
|
||||
python icons/retheme.py --dry-run
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
REPO_ROOT = SCRIPT_DIR.parent
|
||||
|
||||
DEFAULT_SOURCE = SCRIPT_DIR / "mappings" / "FCAD.csv"
|
||||
DEFAULT_TARGET = SCRIPT_DIR / "mappings" / "kindred.csv"
|
||||
DEFAULT_OUTPUT = SCRIPT_DIR / "themed"
|
||||
|
||||
# Default input dirs: core GUI icons + all module icons
|
||||
DEFAULT_INPUT_DIRS = [
|
||||
REPO_ROOT / "src" / "Gui" / "Icons",
|
||||
*sorted(REPO_ROOT.glob("src/Mod/*/Gui/Resources/icons")),
|
||||
*sorted(REPO_ROOT.glob("src/Mod/*/Resources/icons")),
|
||||
]
|
||||
|
||||
|
||||
def load_palette(path: Path) -> list[list[str]]:
|
||||
"""Load a palette CSV. Each row is a list of hex color strings."""
|
||||
rows = []
|
||||
with open(path) as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
colors = []
|
||||
for cell in row:
|
||||
cell = cell.strip()
|
||||
if cell:
|
||||
if not cell.startswith("#"):
|
||||
cell = "#" + cell
|
||||
colors.append(cell.lower())
|
||||
if colors:
|
||||
rows.append(colors)
|
||||
return rows
|
||||
|
||||
|
||||
def build_mapping(source_path: Path, target_path: Path) -> dict[str, str]:
|
||||
"""Build a {source_hex: target_hex} dict from two palette CSVs."""
|
||||
source = load_palette(source_path)
|
||||
target = load_palette(target_path)
|
||||
|
||||
if len(source) != len(target):
|
||||
print(
|
||||
f"Error: palette row count mismatch: "
|
||||
f"{source_path.name} has {len(source)} rows, "
|
||||
f"{target_path.name} has {len(target)} rows",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
mapping = {}
|
||||
for i, (src_row, tgt_row) in enumerate(zip(source, target)):
|
||||
if len(src_row) != len(tgt_row):
|
||||
print(
|
||||
f"Error: column count mismatch on row {i + 1}: "
|
||||
f"{len(src_row)} source colors vs {len(tgt_row)} target colors",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
for src, tgt in zip(src_row, tgt_row):
|
||||
mapping[src] = tgt
|
||||
|
||||
return mapping
|
||||
|
||||
|
||||
def retheme_svg(content: str, mapping: dict[str, str]) -> tuple[str, dict[str, int]]:
|
||||
"""Replace all mapped hex colors in SVG content.
|
||||
|
||||
Returns the modified content and a dict of {color: replacement_count}.
|
||||
"""
|
||||
stats: dict[str, int] = {}
|
||||
|
||||
def replacer(match: re.Match) -> str:
|
||||
color = match.group(0).lower()
|
||||
target = mapping.get(color)
|
||||
if target is not None:
|
||||
stats[color] = stats.get(color, 0) + 1
|
||||
# Preserve original case style (all-lower for consistency)
|
||||
return target
|
||||
return match.group(0)
|
||||
|
||||
result = re.sub(r"#[0-9a-fA-F]{6}\b", replacer, content)
|
||||
return result, stats
|
||||
|
||||
|
||||
def collect_svgs(input_dirs: list[Path]) -> list[Path]:
|
||||
"""Collect all .svg files from input directories, recursively."""
|
||||
svgs = []
|
||||
for d in input_dirs:
|
||||
if d.is_dir():
|
||||
svgs.extend(sorted(d.rglob("*.svg")))
|
||||
return svgs
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--source-palette",
|
||||
type=Path,
|
||||
default=DEFAULT_SOURCE,
|
||||
help=f"Source palette CSV (default: {DEFAULT_SOURCE.relative_to(REPO_ROOT)})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target-palette",
|
||||
type=Path,
|
||||
default=DEFAULT_TARGET,
|
||||
help=f"Target palette CSV (default: {DEFAULT_TARGET.relative_to(REPO_ROOT)})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-dir",
|
||||
type=Path,
|
||||
action="append",
|
||||
dest="input_dirs",
|
||||
help="Input directory containing SVGs (can be repeated; default: FreeCAD icon dirs)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
type=Path,
|
||||
default=DEFAULT_OUTPUT,
|
||||
help=f"Output directory for themed SVGs (default: {DEFAULT_OUTPUT.relative_to(REPO_ROOT)})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Show what would be done without writing files",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
input_dirs = args.input_dirs or DEFAULT_INPUT_DIRS
|
||||
|
||||
# Build color mapping
|
||||
mapping = build_mapping(args.source_palette, args.target_palette)
|
||||
print(f"Loaded {len(mapping)} color mappings")
|
||||
for src, tgt in mapping.items():
|
||||
print(f" {src} -> {tgt}")
|
||||
|
||||
# Collect SVGs
|
||||
svgs = collect_svgs(input_dirs)
|
||||
print(f"\nFound {len(svgs)} SVG files across {len(input_dirs)} directories")
|
||||
|
||||
if not svgs:
|
||||
print("No SVGs found. Check --input-dir paths.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Process
|
||||
if not args.dry_run:
|
||||
args.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
total_files = 0
|
||||
total_replacements = 0
|
||||
all_unmapped: dict[str, int] = {}
|
||||
seen_names: set[str] = set()
|
||||
|
||||
for svg_path in svgs:
|
||||
# Skip duplicates (same filename from different subdirectories)
|
||||
if svg_path.name in seen_names:
|
||||
continue
|
||||
seen_names.add(svg_path.name)
|
||||
|
||||
content = svg_path.read_text(encoding="utf-8")
|
||||
|
||||
themed, stats = retheme_svg(content, mapping)
|
||||
|
||||
total_files += 1
|
||||
file_replacements = sum(stats.values())
|
||||
total_replacements += file_replacements
|
||||
|
||||
if not args.dry_run:
|
||||
out_path = args.output_dir / svg_path.name
|
||||
out_path.write_text(themed, encoding="utf-8")
|
||||
|
||||
# Track unmapped colors in this file
|
||||
for match in re.finditer(r"#[0-9a-fA-F]{6}\b", content):
|
||||
color = match.group(0).lower()
|
||||
if color not in mapping:
|
||||
all_unmapped[color] = all_unmapped.get(color, 0) + 1
|
||||
|
||||
# Summary
|
||||
action = "Would write" if args.dry_run else "Wrote"
|
||||
print(
|
||||
f"\n{action} {total_files} themed SVGs with {total_replacements} color replacements"
|
||||
)
|
||||
print(f" Output: {args.output_dir}")
|
||||
|
||||
if all_unmapped:
|
||||
print(f"\nUnmapped colors ({len(all_unmapped)} unique):")
|
||||
for color, count in sorted(all_unmapped.items(), key=lambda x: -x[1])[:20]:
|
||||
print(f" {color} ({count} occurrences)")
|
||||
if len(all_unmapped) > 20:
|
||||
print(f" ... and {len(all_unmapped) - 20} more")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
159
icons/themed/AddonManager.svg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
64
icons/themed/Arch_3Views.svg
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg2985" version="1.1" inkscape:version="0.48.5 r10040" sodipodi:docname="Arch_3Views.svg">
|
||||
<defs id="defs2987">
|
||||
<inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 32 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="64 : 32 : 1" inkscape:persp3d-origin="32 : 21.333333 : 1" id="perspective2993"/>
|
||||
</defs>
|
||||
<sodipodi:namedview id="base" pagecolor="#cdd6f4" bordercolor="#38394b" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2.9062855" inkscape:cx="55.690563" inkscape:cy="28.554415" inkscape:current-layer="g5297" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="800" inkscape:window-height="837" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="0" inkscape:snap-global="true">
|
||||
<inkscape:grid type="xygrid" id="grid2992" empspacing="2" visible="true" enabled="true" snapvisiblegridlinesonly="true"/>
|
||||
</sodipodi:namedview>
|
||||
<metadata id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_3Views</dc:title>
|
||||
<dc:date>2014-08-29</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_3Views.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
|
||||
<g id="g5297" transform="translate(10.542319,6.1711137)">
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3009-7-2" d="m 18.457681,20.828886 -14,-8 0,34 14,8 z" style="color:#11111b;fill:#6cd163;fill-opacity:1;fill-rule:nonzero;stroke:#1c5017;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3009-6-0-8" d="m 34.457681,12.828886 -16,8 0,34 16,-8 z" style="color:#11111b;fill:#359b2e;fill-opacity:1;fill-rule:nonzero;stroke:#1c5017;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3029-8-6" d="m 4.457681,12.828886 16,-7.9999997 14,7.9999997 -16,8 z" style="color:#11111b;fill:#a6e3a1;fill-opacity:1;fill-rule:nonzero;stroke:#1c5017;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
<path style="fill:none;stroke:#a6e3a1;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 6.475023,16.273948 -0.034684,29.38152 10.017342,5.757214 0,-29.410378 z" id="path2994" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
|
||||
<path inkscape:connector-curvature="0" id="path3055" d="m 4.457681,12.828886 14,42" style="color:#11111b;fill:#89da82;fill-opacity:1;fill-rule:nonzero;stroke:#1c5017;stroke-width:1.85461509;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" sodipodi:nodetypes="cc"/>
|
||||
<path style="fill:none;stroke:#6cd163;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 20.44752,22.035362 0,29.567809 12.052567,-6.000271 -0.01734,-29.550467 z" id="path2996" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
|
||||
<path inkscape:connector-curvature="0" id="path3057" d="m 18.457681,54.828886 16,-42 -28.741113,-0.0445" style="color:#11111b;fill:none;stroke:#1c5017;stroke-width:1.85461509;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" sodipodi:nodetypes="ccc"/>
|
||||
<g id="g3813" transform="translate(2,0)">
|
||||
<path style="color:#11111b;fill:#0846b3;fill-opacity:1;fill-rule:nonzero;stroke:#052459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 42.485658,22.702462 -16,8 -0.02798,24.126424 16,0 z" id="path3009-6-0-8-3" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path2996-1" d="m 28.475497,31.908938 -0.01782,20.919948 12,0 0.05304,-26.902876 z" style="fill:none;stroke:#307bf7;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||
</g>
|
||||
<g id="g3856" transform="translate(2,0)">
|
||||
<path style="color:#11111b;fill:#307bf7;fill-opacity:1;fill-rule:nonzero;stroke:#052459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 8.457681,30.828886 -14,-8 0,32 14,0 z" id="path3009-7-2-2" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path2994-7" d="m -3.524977,26.273949 -0.017342,26.554937 10,0 0,-20.826582 z" style="fill:#307bf7;stroke:#89b4fa;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||
</g>
|
||||
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path3029-8-6-7" d="m 4.457681,4.828886 16,-7.9999997 14,7.9999997 -16,8 z" style="color:#11111b;fill:#89b4fa;fill-opacity:1;fill-rule:nonzero;stroke:#052459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
71
icons/themed/Arch_Add.svg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
335
icons/themed/Arch_Axis.svg
Normal file
@@ -0,0 +1,335 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Axis.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3896"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3898"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3900"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3877">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3879" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3881" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3812">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3814" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3816" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3804">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3806" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3808" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3796">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3798" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3800" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3883">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3793">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3793-2"
|
||||
id="linearGradient3799-8"
|
||||
x1="12.037806"
|
||||
y1="54.001419"
|
||||
x2="52.882648"
|
||||
y2="9.274148"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3793-2">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795-6" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3883-6"
|
||||
id="linearGradient3889-4"
|
||||
x1="3"
|
||||
y1="31.671875"
|
||||
x2="59.25"
|
||||
y2="31.671875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2727273,-0.18181818)" />
|
||||
<linearGradient
|
||||
id="linearGradient3883-6">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885-4" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3796"
|
||||
id="linearGradient3802"
|
||||
x1="16.4375"
|
||||
y1="59.705883"
|
||||
x2="8.5625"
|
||||
y2="40.294117"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3804"
|
||||
id="linearGradient3810"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.5625"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3812"
|
||||
id="linearGradient3818"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.562501"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3886"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-11.6,-54.6)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3877"
|
||||
id="linearGradient3888"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-11.6,-28.6)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.7232161"
|
||||
inkscape:cx="73.255013"
|
||||
inkscape:cy="31.608623"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2999"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Axis</dc:title>
|
||||
<dc:date>2011-12-12</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040"
|
||||
width="40"
|
||||
height="6"
|
||||
x="22"
|
||||
y="-48"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3042"
|
||||
width="40"
|
||||
height="6"
|
||||
x="22"
|
||||
y="-22"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6"
|
||||
cx="14"
|
||||
cy="-19"
|
||||
r="10"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3"
|
||||
cx="14"
|
||||
cy="-45"
|
||||
r="10"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5"
|
||||
width="39"
|
||||
height="4"
|
||||
x="22"
|
||||
y="-47"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3042-3"
|
||||
width="39"
|
||||
height="4"
|
||||
x="22"
|
||||
y="-21"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:url(#linearGradient3888);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-6"
|
||||
cx="14"
|
||||
cy="-19"
|
||||
r="8"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:url(#linearGradient3886);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-2"
|
||||
cx="14"
|
||||
cy="-45"
|
||||
r="8"
|
||||
transform="rotate(90)" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 18,22 V 61"
|
||||
id="path3910"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 44,22 V 61"
|
||||
id="path3910-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
426
icons/themed/Arch_Axis_System.svg
Normal file
@@ -0,0 +1,426 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Axis_System.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3896"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3898"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3900"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3812">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3814" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3816" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3804">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3806" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3808" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3796">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3798" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3800" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3883">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3793">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3793-2"
|
||||
id="linearGradient3799-8"
|
||||
x1="12.037806"
|
||||
y1="54.001419"
|
||||
x2="52.882648"
|
||||
y2="9.274148"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3793-2">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795-6" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3883-6"
|
||||
id="linearGradient3889-4"
|
||||
x1="3"
|
||||
y1="31.671875"
|
||||
x2="59.25"
|
||||
y2="31.671875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2727273,-0.18181818)" />
|
||||
<linearGradient
|
||||
id="linearGradient3883-6">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885-4" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3796"
|
||||
id="linearGradient3802"
|
||||
x1="16.4375"
|
||||
y1="59.705883"
|
||||
x2="8.5625"
|
||||
y2="40.294117"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3804"
|
||||
id="linearGradient3810"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.5625"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3812"
|
||||
id="linearGradient3818"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.562501"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-12.6,18.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3886-0"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-12.6,40.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3888-6"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,4.4,3.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3884-2"
|
||||
x1="34.5"
|
||||
y1="20.75"
|
||||
x2="27"
|
||||
y2="3.25"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,26.4,3.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3884-2-4"
|
||||
x1="34.5"
|
||||
y1="20.75"
|
||||
x2="27"
|
||||
y2="3.25"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="6.6796362"
|
||||
inkscape:cx="33.405573"
|
||||
inkscape:cy="42.101045"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2999"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Axis</dc:title>
|
||||
<dc:date>2011-12-12</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3044-8"
|
||||
width="6"
|
||||
height="40"
|
||||
x="27"
|
||||
y="21" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="13"
|
||||
cx="30"
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-7" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040-9"
|
||||
width="40"
|
||||
height="6"
|
||||
x="21"
|
||||
y="25" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3042-2"
|
||||
width="40"
|
||||
height="6"
|
||||
x="21"
|
||||
y="47" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="50"
|
||||
cx="13"
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-0" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-2"
|
||||
width="4"
|
||||
height="39"
|
||||
x="28"
|
||||
y="21" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="28"
|
||||
cx="13"
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-3" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3044-8-5"
|
||||
width="6"
|
||||
height="40"
|
||||
x="49"
|
||||
y="21" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5-7"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="26" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3042-3-5"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="48" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="13"
|
||||
cx="30"
|
||||
style="fill:url(#linearGradient3884-2);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-5-9" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="50"
|
||||
cx="13"
|
||||
style="fill:url(#linearGradient3888-6);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-6-2" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="28"
|
||||
cx="13"
|
||||
style="fill:url(#linearGradient3886-0);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-2-2" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 21,27 h 8 v -6"
|
||||
id="path3902-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 21,49 h 8 V 31"
|
||||
id="path3904-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 29,60 V 52"
|
||||
id="path3906-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 32,49 H 60"
|
||||
id="path3910-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="13"
|
||||
cx="52"
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-7-7" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-2-4"
|
||||
width="4"
|
||||
height="39"
|
||||
x="50"
|
||||
y="21" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 32,27 H 50"
|
||||
id="path3908-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="13"
|
||||
cx="52"
|
||||
style="fill:url(#linearGradient3884-2-4);fill-opacity:1;stroke:#f9e2af;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-5-9-9" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,60 V 52"
|
||||
id="path3906-7-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,50 V 30"
|
||||
id="path3906-7-9-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,28 V 20"
|
||||
id="path3906-7-9-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54,27 h 6"
|
||||
id="path3910-6-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
421
icons/themed/Arch_Axis_System_Tree.svg
Normal file
@@ -0,0 +1,421 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Axis_System_Tree.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3896"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3898"
|
||||
offset="0"
|
||||
style="stop-color:#6c7086;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3900"
|
||||
offset="1"
|
||||
style="stop-color:#cdd6f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3812">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3814" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3816" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3804">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3806" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3808" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3796">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3798" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3800" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3883">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3793">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3793-2"
|
||||
id="linearGradient3799-8"
|
||||
x1="12.037806"
|
||||
y1="54.001419"
|
||||
x2="52.882648"
|
||||
y2="9.274148"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3793-2">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795-6" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3883-6"
|
||||
id="linearGradient3889-4"
|
||||
x1="3"
|
||||
y1="31.671875"
|
||||
x2="59.25"
|
||||
y2="31.671875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2727273,-0.18181818)" />
|
||||
<linearGradient
|
||||
id="linearGradient3883-6">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885-4" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3796"
|
||||
id="linearGradient3802"
|
||||
x1="16.4375"
|
||||
y1="59.705883"
|
||||
x2="8.5625"
|
||||
y2="40.294117"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3804"
|
||||
id="linearGradient3810"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.5625"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3812"
|
||||
id="linearGradient3818"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.562501"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-12.6,18.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3886-1"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-12.6,40.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3888-8"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,4.4,3.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3884-1"
|
||||
x1="34.5"
|
||||
y1="20.75"
|
||||
x2="27"
|
||||
y2="3.25"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.8,0,0,0.8,26.4,3.4)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3884-1-4"
|
||||
x1="34.5"
|
||||
y1="20.75"
|
||||
x2="27"
|
||||
y2="3.25"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="6.189996"
|
||||
inkscape:cx="12.900184"
|
||||
inkscape:cy="29.6413"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2999"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Axis_Tree</dc:title>
|
||||
<dc:date>2011-12-12</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis_Tree.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3044-0"
|
||||
width="6"
|
||||
height="40"
|
||||
x="27"
|
||||
y="21" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="13"
|
||||
cx="30"
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-4" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040-4"
|
||||
width="40"
|
||||
height="6"
|
||||
x="21"
|
||||
y="25" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3044-0-0"
|
||||
width="6"
|
||||
height="40"
|
||||
x="49"
|
||||
y="21" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3042-4"
|
||||
width="40"
|
||||
height="6"
|
||||
x="21"
|
||||
y="47" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="50"
|
||||
cx="13"
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-4" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-7"
|
||||
width="4"
|
||||
height="39"
|
||||
x="28"
|
||||
y="21" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="28"
|
||||
cx="13"
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-6" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5-3"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="26" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3042-3-1"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="48" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="13"
|
||||
cx="30"
|
||||
style="fill:url(#linearGradient3884-1);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-5-7" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="50"
|
||||
cx="13"
|
||||
style="fill:url(#linearGradient3888-8);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-6-5" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="28"
|
||||
cx="13"
|
||||
style="fill:url(#linearGradient3886-1);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-2-9" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 21,27 h 8 v -6"
|
||||
id="path3902-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 21,49 h 8 V 31"
|
||||
id="path3904-2"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 29,60 V 52"
|
||||
id="path3906-1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 36,27 H 60"
|
||||
id="path3908-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 32,49 H 60"
|
||||
id="path3910-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<circle
|
||||
r="10"
|
||||
cy="13"
|
||||
cx="52"
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-4-8" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-7-6"
|
||||
width="4"
|
||||
height="39"
|
||||
x="50"
|
||||
y="21" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="13"
|
||||
cx="52"
|
||||
style="fill:url(#linearGradient3884-1-4);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-5-7-2" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 32,27 H 51 V 21"
|
||||
id="path3902-6-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,60 V 52"
|
||||
id="path3906-1-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,50 V 30"
|
||||
id="path3906-1-7-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
335
icons/themed/Arch_Axis_Tree.svg
Normal file
@@ -0,0 +1,335 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Axis_Tree.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3896"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3898"
|
||||
offset="0"
|
||||
style="stop-color:#6c7086;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3900"
|
||||
offset="1"
|
||||
style="stop-color:#cdd6f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3877">
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3879" />
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3881" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3812">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3814" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3816" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3804">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3806" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3808" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3796">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3798" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3800" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3883">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3793">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3793-2"
|
||||
id="linearGradient3799-8"
|
||||
x1="12.037806"
|
||||
y1="54.001419"
|
||||
x2="52.882648"
|
||||
y2="9.274148"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3793-2">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795-6" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3883-6"
|
||||
id="linearGradient3889-4"
|
||||
x1="3"
|
||||
y1="31.671875"
|
||||
x2="59.25"
|
||||
y2="31.671875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2727273,-0.18181818)" />
|
||||
<linearGradient
|
||||
id="linearGradient3883-6">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885-4" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3796"
|
||||
id="linearGradient3802"
|
||||
x1="16.4375"
|
||||
y1="59.705883"
|
||||
x2="8.5625"
|
||||
y2="40.294117"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3804"
|
||||
id="linearGradient3810"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.5625"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3812"
|
||||
id="linearGradient3818"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.562501"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3896"
|
||||
id="linearGradient3886"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-11.6,-54.6)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3877"
|
||||
id="linearGradient3888"
|
||||
x1="35.75"
|
||||
y1="19.5"
|
||||
x2="28.25"
|
||||
y2="4.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8,0,0,0.8,-11.6,-28.6)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.3769881"
|
||||
inkscape:cx="47.483737"
|
||||
inkscape:cy="15.934805"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2999"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Axis_Tree</dc:title>
|
||||
<dc:date>2011-12-12</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis_Tree.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040"
|
||||
width="40"
|
||||
height="6"
|
||||
x="22"
|
||||
y="-48"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3042"
|
||||
width="40"
|
||||
height="6"
|
||||
x="22"
|
||||
y="-22"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6"
|
||||
cx="14"
|
||||
cy="-19"
|
||||
r="10"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3"
|
||||
cx="14"
|
||||
cy="-45"
|
||||
r="10"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5"
|
||||
width="39"
|
||||
height="4"
|
||||
x="22"
|
||||
y="-47"
|
||||
transform="rotate(90)" />
|
||||
<rect
|
||||
style="fill:#6c7086;fill-opacity:1;stroke:none"
|
||||
id="rect3042-3"
|
||||
width="39"
|
||||
height="4"
|
||||
x="22"
|
||||
y="-21"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:url(#linearGradient3888);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-6-6"
|
||||
cx="14"
|
||||
cy="-19"
|
||||
r="8"
|
||||
transform="rotate(90)" />
|
||||
<circle
|
||||
style="fill:url(#linearGradient3886);fill-opacity:1;stroke:#cdd6f4;stroke-width:2.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="path3013-3-2"
|
||||
cx="14"
|
||||
cy="-45"
|
||||
r="8"
|
||||
transform="rotate(90)" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 44,61 V 22"
|
||||
id="path3906-1-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 18,61 V 22"
|
||||
id="path3906-1-9-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
454
icons/themed/Arch_Bimserver.svg
Normal file
@@ -0,0 +1,454 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48.000000px"
|
||||
height="48.000000px"
|
||||
id="svg249"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.5 r10040"
|
||||
sodipodi:docname="drawing-draft-view.svg"
|
||||
inkscape:export-filename="/home/jimmac/gfx/novell/pdes/trunk/docs/BIGmime-text.png"
|
||||
inkscape:export-xdpi="240.00000"
|
||||
inkscape:export-ydpi="240.00000"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient5031"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5060">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5062" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5064" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient5029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
id="linearGradient5048">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop5050" />
|
||||
<stop
|
||||
id="stop5056"
|
||||
offset="0.5"
|
||||
style="stop-color:black;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5052" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5048"
|
||||
id="linearGradient5027"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
|
||||
x1="302.85715"
|
||||
y1="366.64789"
|
||||
x2="302.85715"
|
||||
y2="609.50507" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4542">
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4544" />
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4546" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4542"
|
||||
id="radialGradient4548"
|
||||
cx="24.306795"
|
||||
cy="42.07798"
|
||||
fx="24.306795"
|
||||
fy="42.07798"
|
||||
r="15.821514"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.284916,-6.310056e-16,30.08928)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient15662">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop15664" />
|
||||
<stop
|
||||
style="stop-color:#afb6d2;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop15666" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="64.5679"
|
||||
fx="20.8921"
|
||||
r="5.257"
|
||||
cy="64.5679"
|
||||
cx="20.8921"
|
||||
id="aigrd3">
|
||||
<stop
|
||||
id="stop15573"
|
||||
style="stop-color:#8c92ab"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15575"
|
||||
style="stop-color:#585b70;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
fy="114.5684"
|
||||
fx="20.8921"
|
||||
r="5.256"
|
||||
cy="114.5684"
|
||||
cx="20.8921"
|
||||
id="aigrd2">
|
||||
<stop
|
||||
id="stop15566"
|
||||
style="stop-color:#8c92ab"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop15568"
|
||||
style="stop-color:#585b70;stop-opacity:1.0000000;"
|
||||
offset="1.0000000" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="linearGradient269">
|
||||
<stop
|
||||
style="stop-color:#585b70;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop270" />
|
||||
<stop
|
||||
style="stop-color:#2c2d3e;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop271" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient259">
|
||||
<stop
|
||||
style="stop-color:#b7bfdc;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop260" />
|
||||
<stop
|
||||
style="stop-color:#595c71;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop261" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient12512">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop12513" />
|
||||
<stop
|
||||
style="stop-color:#f9d487;stop-opacity:0.89108908;"
|
||||
offset="0.50000000"
|
||||
id="stop12517" />
|
||||
<stop
|
||||
style="stop-color:#f8ca69;stop-opacity:0.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop12514" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="37.751713"
|
||||
fy="3.7561285"
|
||||
fx="8.8244190"
|
||||
cy="3.7561285"
|
||||
cx="8.8244190"
|
||||
gradientTransform="matrix(0.96827297,0,0,1.032767,29.045513,-115.18343)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient15656"
|
||||
xlink:href="#linearGradient269"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="86.708450"
|
||||
fy="35.736916"
|
||||
fx="33.966679"
|
||||
cy="35.736916"
|
||||
cx="33.966679"
|
||||
gradientTransform="matrix(0.96049297,0,0,1.041132,25.691961,-115.82988)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient15658"
|
||||
xlink:href="#linearGradient259"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="38.158695"
|
||||
fy="7.2678967"
|
||||
fx="8.1435566"
|
||||
cy="7.2678967"
|
||||
cx="8.1435566"
|
||||
gradientTransform="matrix(0.96827297,0,0,1.032767,29.045513,-115.18343)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient15668"
|
||||
xlink:href="#linearGradient15662"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#aigrd2"
|
||||
id="radialGradient2283"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)"
|
||||
cx="20.8921"
|
||||
cy="114.5684"
|
||||
fx="20.8921"
|
||||
fy="114.5684"
|
||||
r="5.256" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#aigrd3"
|
||||
id="radialGradient2285"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)"
|
||||
cx="20.8921"
|
||||
cy="64.5679"
|
||||
fx="20.8921"
|
||||
fy="64.5679"
|
||||
r="5.257" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377-76"
|
||||
id="linearGradient4343"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="18.971846"
|
||||
y1="14.452502"
|
||||
x2="44.524982"
|
||||
y2="41.792759" />
|
||||
<linearGradient
|
||||
id="linearGradient3377-76">
|
||||
<stop
|
||||
style="stop-color:#f9d791;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3379-5" />
|
||||
<stop
|
||||
id="stop4345"
|
||||
offset="0.5"
|
||||
style="stop-color:#fcb915;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#c68708;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3381-7" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377-76"
|
||||
id="linearGradient4349"
|
||||
x1="145.64697"
|
||||
y1="79.160103"
|
||||
x2="175.6825"
|
||||
y2="108.75008"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient4482">
|
||||
<stop
|
||||
style="stop-color:#f9d791;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4484" />
|
||||
<stop
|
||||
id="stop4486"
|
||||
offset="0.5"
|
||||
style="stop-color:#fcb915;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#c68708;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4488" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient4351"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)"
|
||||
cx="135.38333"
|
||||
cy="97.369568"
|
||||
fx="135.38333"
|
||||
fy="97.369568"
|
||||
r="19.467436" />
|
||||
<linearGradient
|
||||
id="linearGradient3377">
|
||||
<stop
|
||||
style="stop-color:#f9d791;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3379" />
|
||||
<stop
|
||||
style="stop-color:#f8ca69;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3381" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient4353"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="45.883327"
|
||||
cy="28.869568"
|
||||
fx="45.883327"
|
||||
fy="28.869568"
|
||||
r="19.467436" />
|
||||
<linearGradient
|
||||
id="linearGradient4495">
|
||||
<stop
|
||||
style="stop-color:#f9d791;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4497" />
|
||||
<stop
|
||||
style="stop-color:#f8ca69;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4499" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="0.32941176"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.01908"
|
||||
inkscape:cx="33.4692"
|
||||
inkscape:cy="19.044121"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1053"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:object-nodes="true" />
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Shadow"
|
||||
id="layer6"
|
||||
inkscape:groupmode="layer" />
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Base"
|
||||
inkscape:groupmode="layer"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="fill:#696969;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;color:#11111b;fill-opacity:1;fill-rule:nonzero;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 25.319719,16.100786 c 0,0 -7.033257,0.862141 -7.033257,0.862141 l 0.64402,21.218891 6.481285,-2.117647 z"
|
||||
id="path3092"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#2d5b89;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="m 6.4433689,15.964659 11.0263281,5.490476 c 0,0 0.998269,25.047462 0.862141,24.775207 C 18.195711,45.958087 7.8953957,35.703148 7.8953957,35.703148 z"
|
||||
id="path3082"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#535353;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;color:#11111b;fill-opacity:1;fill-rule:nonzero;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 25.319717,16.100786 0.09205,19.963385 7.031959,4.94795 0.862141,-22.23416 -7.986148,-2.677175 z"
|
||||
id="path3090"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#23476b;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="m 6.4433689,15.964659 c 0,0 19.1032271,-2.495671 19.4208581,-2.450295 0.317631,0.04537 14.06651,3.993073 14.06651,3.993073 l -6.624872,1.270524 -7.986148,-2.677175 -7.033255,0.862141 7.396262,3.085557 -8.213027,1.406651 z"
|
||||
id="path3084"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#3a74ae;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="m 17.469697,21.455135 8.213027,-1.406651 -0.136128,23.55006 -7.124006,2.654486 z"
|
||||
id="path3086"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#3a74ae;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;color:#11111b;fill-opacity:1;fill-rule:nonzero;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 33.305865,18.777961 6.624872,-1.270524 -1.08902,21.099765 -6.397993,2.404919 z"
|
||||
id="path3088"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#535353;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 17.87808,2.9871693 18.014207,9.9750483 25.7281,11.880833 25.68272,3.7131827 z"
|
||||
id="path3094"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#414141;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 25.68272,3.7131827 33.804999,3.3955518 25.138214,2.7149143 17.87808,2.9871693 z"
|
||||
id="path3096"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#696969;stroke:#11111b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 25.68272,3.7131827 33.804999,3.3955518 33.532744,11.064068 25.7281,11.880833 z"
|
||||
id="path3098"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="new"
|
||||
style="display:inline" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
125
icons/themed/Arch_Building.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
494
icons/themed/Arch_BuildingPart.svg
Normal file
@@ -0,0 +1,494 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="Arch_BuildingPart.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient3071"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3073"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3075"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3633">
|
||||
<stop
|
||||
style="stop-color:#fff652;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3635" />
|
||||
<stop
|
||||
style="stop-color:#ffbf00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3637" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3866"
|
||||
id="linearGradient3872"
|
||||
x1="35"
|
||||
y1="53"
|
||||
x2="24"
|
||||
y2="9"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3866">
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3868" />
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3870" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="9"
|
||||
x2="24"
|
||||
y1="64"
|
||||
x1="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3120"
|
||||
xlink:href="#linearGradient3071"
|
||||
inkscape:collect="always"
|
||||
gradientTransform="translate(70,1)" />
|
||||
<linearGradient
|
||||
y2="9"
|
||||
x2="24"
|
||||
y1="64"
|
||||
x1="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3120-3"
|
||||
xlink:href="#linearGradient3071"
|
||||
inkscape:collect="always"
|
||||
gradientTransform="translate(-2,-8)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3071"
|
||||
id="linearGradient1065"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(70,1)"
|
||||
x1="-44.80624"
|
||||
y1="48.42857"
|
||||
x2="-44.80624"
|
||||
y2="12.523807" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="10.162079"
|
||||
inkscape:cx="36.903644"
|
||||
inkscape:cy="30.674644"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3032"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Floor</dc:title>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3067"
|
||||
transform="matrix(1.4966666,0,0,1.6153846,-9.7066615,-19.846149)"
|
||||
style="fill:url(#linearGradient3120);font-variant-east_asian:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke:#664506;stroke-width:1.28626216;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect5347"
|
||||
d="m 7.9109119,18.476189 v 4 22 h 2 2.0000001 l 13.28285,-10e-7 V 39.523807 H 13.167036 v -7.428572 h 9.35412 v -3.714286 h -9.35412 l -10e-7,-3.714285 h 4.00891 v -6.190476 z m 18.6191531,-1e-6 v 6.190476 h 5.345212 v 7.428571 h 4.008909 v -7.428571 h 5.345212 v 14.857143 h -5.126544 v -2.476191 h -4.227577 v 2.476191 l -1.336304,0 v 4.95238 l 1.918001,2e-6 h 3 8.453938 2 2 v -26 z"
|
||||
style="color:#11111b;display:inline;overflow:visible;visibility:visible;vector-effect:none;fill:url(#linearGradient1065);fill-opacity:1;fill-rule:nonzero;stroke:#664506;stroke-width:1.28626215;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
</g>
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 15,12 H 4 v 38 h 23"
|
||||
id="path1042"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 31,12 H 60 V 50 H 37"
|
||||
id="path1044"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
462
icons/themed/Arch_BuildingPart_Tree.svg
Normal file
@@ -0,0 +1,462 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="Arch_BuildingPart_Tree.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient3071"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3073"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3075"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3633">
|
||||
<stop
|
||||
style="stop-color:#fff652;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3635" />
|
||||
<stop
|
||||
style="stop-color:#ffbf00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3637" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3866"
|
||||
id="linearGradient3872"
|
||||
x1="35"
|
||||
y1="53"
|
||||
x2="24"
|
||||
y2="9"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3866">
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3868" />
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3870" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="9"
|
||||
x2="24"
|
||||
y1="64"
|
||||
x1="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3120-3"
|
||||
xlink:href="#linearGradient3071"
|
||||
inkscape:collect="always"
|
||||
gradientTransform="translate(-2,-8)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="10.162079"
|
||||
inkscape:cx="36.903644"
|
||||
inkscape:cy="30.674644"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3032"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Floor</dc:title>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3067"
|
||||
transform="matrix(1.4966666,0,0,1.6153846,-9.7066615,-19.846149)"
|
||||
style="fill:#cdd6f4;font-variant-east_asian:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke:#22200e;stroke-width:1.70151215;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect5347"
|
||||
d="m 7.9109119,18.476189 v 4 22 h 2 2.0000001 l 13.28285,-10e-7 V 39.523807 H 13.167036 v -7.428572 h 9.35412 v -3.714286 h -9.35412 l -10e-7,-3.714285 h 4.00891 v -6.190476 z m 18.6191531,-1e-6 v 6.190476 h 5.345212 v 7.428571 h 4.008909 v -7.428571 h 5.345212 v 14.857143 h -5.126544 v -2.476191 h -4.227577 v 2.476191 l -1.336304,0 v 4.95238 l 1.918001,2e-6 h 3 8.453938 2 2 v -26 z"
|
||||
style="color:#11111b;display:inline;overflow:visible;visibility:visible;vector-effect:none;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:#22200e;stroke-width:1.70151215;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
125
icons/themed/Arch_Building_Tree.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
130
icons/themed/Arch_Cell.svg
Normal file
|
After Width: | Height: | Size: 18 KiB |
130
icons/themed/Arch_Cell_Tree.svg
Normal file
|
After Width: | Height: | Size: 18 KiB |
75
icons/themed/Arch_Check.svg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
67
icons/themed/Arch_CloseHoles.svg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
580
icons/themed/Arch_Component.svg
Normal file
@@ -0,0 +1,580 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2980"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
|
||||
sodipodi:docname="Arch_Component.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2982">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3805">
|
||||
<stop
|
||||
style="stop-color:#359b2e;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3807" />
|
||||
<stop
|
||||
style="stop-color:#a6e3a1;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3809" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#89b4fa;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#0841a6;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3850"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
|
||||
cx="51.328892"
|
||||
cy="31.074146"
|
||||
fx="51.328892"
|
||||
fy="31.074146"
|
||||
r="19.571428" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2988" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3805"
|
||||
id="linearGradient3811"
|
||||
x1="49.058823"
|
||||
y1="60.823528"
|
||||
x2="34.941177"
|
||||
y2="23.17647"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3838">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3840" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3842" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3828">
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3830" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3832" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3633">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3635" />
|
||||
<stop
|
||||
style="stop-color:#ffbf00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3637" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785-6"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785-1"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785-67"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3848"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3869"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3894"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3828"
|
||||
id="linearGradient1162"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-59.940632,-24.87265)"
|
||||
x1="69.43573"
|
||||
y1="81.495598"
|
||||
x2="86.047386"
|
||||
y2="43.697762" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3838"
|
||||
id="linearGradient1189"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-81.017888,-10.36525)"
|
||||
x1="130.59373"
|
||||
y1="63.193493"
|
||||
x2="129.11099"
|
||||
y2="20.605619" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8.1608652"
|
||||
inkscape:cx="39.093046"
|
||||
inkscape:cy="33.251441"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:document-rotation="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2991"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2985">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Component</dc:title>
|
||||
<dc:date>2015-04-08</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Component.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="fill:url(#linearGradient1189);fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stop-color:#11111b;stop-opacity:1"
|
||||
d="M 36.358639,16.058671 36.236103,46.422014 12.008657,56.584475 12.236103,18.422014 Z"
|
||||
id="path2995-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#f9e2af;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stop-color:#11111b;stop-opacity:1"
|
||||
d="M 3,17 37,23 61,15 31,11 z"
|
||||
id="path2993"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient1189);stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stop-color:#11111b;stop-opacity:1"
|
||||
d="M 61,15 61,51 37,61 37,23 z"
|
||||
id="path2995"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path3825"
|
||||
style="fill:url(#linearGradient1162);fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-variation-settings:normal;opacity:1;vector-effect:none;stop-color:#11111b;stop-opacity:1"
|
||||
d="M 3 17 L 3 55 L 12 56.587891 L 12 30 L 26 32 L 26 59.058594 L 37 61 L 37 23 L 3 17 z " />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stop-color:#11111b;stop-opacity:1"
|
||||
d="m 27.192817,57.216522 7.824524,1.399113 -0.0087,-33.933614 L 5,19.42772 5.00867,53.346836 10.27166,54.24942"
|
||||
id="path3765"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f8c459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stop-color:#11111b;stop-opacity:1"
|
||||
d="m 39.01243,24.433833 -0.01226,33.535301 20.001105,-8.300993 3.6e-4,-31.867363 z"
|
||||
id="path3775"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
627
icons/themed/Arch_Component_Clone.svg
Normal file
|
After Width: | Height: | Size: 27 KiB |
229
icons/themed/Arch_Component_Tree.svg
Normal file
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2980"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
|
||||
sodipodi:docname="Arch_Component_Tree.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2982">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3805">
|
||||
<stop
|
||||
style="stop-color:#359b2e;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3807" />
|
||||
<stop
|
||||
style="stop-color:#a6e3a1;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3809" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3777">
|
||||
<stop
|
||||
style="stop-color:#45475a;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3779" />
|
||||
<stop
|
||||
style="stop-color:#585b70;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3781" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3767">
|
||||
<stop
|
||||
style="stop-color:#585b70;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3769" />
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3771" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3864">
|
||||
<stop
|
||||
id="stop3866"
|
||||
offset="0"
|
||||
style="stop-color:#89b4fa;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3868"
|
||||
offset="1"
|
||||
style="stop-color:#0841a6;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3864"
|
||||
id="radialGradient3850"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)"
|
||||
cx="51.328892"
|
||||
cy="31.074146"
|
||||
fx="51.328892"
|
||||
fy="31.074146"
|
||||
r="19.571428" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2988" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3767"
|
||||
id="linearGradient3773"
|
||||
x1="22.116516"
|
||||
y1="55.717518"
|
||||
x2="17.328547"
|
||||
y2="21.31134"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3777"
|
||||
id="linearGradient3783"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="47.502235"
|
||||
y2="21.83742"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3805"
|
||||
id="linearGradient3811"
|
||||
x1="49.058823"
|
||||
y1="60.823528"
|
||||
x2="34.941177"
|
||||
y2="23.17647"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3777"
|
||||
id="linearGradient895"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="53.896763"
|
||||
y1="51.179787"
|
||||
x2="47.502235"
|
||||
y2="21.83742"
|
||||
gradientTransform="translate(-24.763897,-4.5779861)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.541206"
|
||||
inkscape:cx="30.574972"
|
||||
inkscape:cy="32.8453"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:document-rotation="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2991"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2985">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Component</dc:title>
|
||||
<dc:date>2015-04-08</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Component.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="fill:url(#linearGradient895);fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 36.358639,16.058671 36.236103,46.422014 12.008657,56.584475 12.236103,18.422014 Z"
|
||||
id="path2995-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#cdd6f4;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 3,17 37,23 61,15 31,11 z"
|
||||
id="path2993"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3783);stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 61,15 61,51 37,61 37,23 z"
|
||||
id="path2995"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path3825"
|
||||
style="fill:url(#linearGradient3773);fill-opacity:1;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 3 17 L 3 55 L 12 56.587891 L 12 30 L 26 32 L 26 59.058594 L 37 61 L 37 23 L 3 17 z " />
|
||||
<path
|
||||
style="fill:none;stroke:#6c7086;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 27.192817,57.216522 7.824524,1.399113 -0.0087,-33.933614 L 5,19.42772 5.00867,53.346836 10.27166,54.24942"
|
||||
id="path3765"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 39.01243,24.433833 -0.01226,33.535301 20.001105,-8.300993 3.6e-4,-31.867363 z"
|
||||
id="path3775"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
227
icons/themed/Arch_CurtainWall.svg
Normal file
@@ -0,0 +1,227 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="Arch_CurtainWall.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3794"
|
||||
id="linearGradient3867"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="32.714748"
|
||||
y1="27.398352"
|
||||
x2="38.997726"
|
||||
y2="3.6523125"
|
||||
gradientTransform="matrix(-0.36199711,-0.85553613,0.73810354,-0.31230866,22.253893,65.739554)"
|
||||
spreadMethod="reflect" />
|
||||
<linearGradient
|
||||
id="linearGradient3794-8">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-5" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886"
|
||||
xlink:href="#linearGradient3794-8"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient3794-1">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-2" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886-0"
|
||||
xlink:href="#linearGradient3794-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3794"
|
||||
id="linearGradient3867-3"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="32.714748"
|
||||
y1="27.398352"
|
||||
x2="38.997726"
|
||||
y2="3.6523125"
|
||||
gradientTransform="matrix(-0.36199711,-0.85553613,0.73810354,-0.31230866,20.172664,63.335227)"
|
||||
spreadMethod="reflect" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.096831"
|
||||
inkscape:cx="35.741065"
|
||||
inkscape:cy="31.523595"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1360"
|
||||
inkscape:window-height="739"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2997"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Site</dc:title>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Site.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="fill:url(#linearGradient3867);fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 6.6299713,45.573855 20.908004,52.532318 39.550895,52.411814 56.057784,60.629029 58.547233,14.153933 39.859557,8.7712607 18.416343,9.7795791 3.081208,3.4042685 Z"
|
||||
id="path3763"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c9a138;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 4.0627415,16.390392 14.7150265,6.474611 20.404836,-0.981002 18.639032,5.886011"
|
||||
id="path890-5"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c9a138;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 5.2974093,30.364138 14.5188257,6.670812 19.227634,-0.784802 17.26563,7.259413"
|
||||
id="path892-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#c9a138;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 6.7565544,43.481706 21.277372,50.578904 38.047346,50.493083 54.4155,57.77384 56.62748,14.385588"
|
||||
id="path3763-7-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:url(#linearGradient3867);fill-opacity:1;fill-rule:evenodd;stroke:#372c0f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 18.639033,9.8487048 20.601037,52.227979"
|
||||
id="path854"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3867);fill-rule:evenodd;stroke:#372c0f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
d="M 39.63247,8.4753024 39.436269,52.62038"
|
||||
id="path856"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c9a138;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 16.639033,9.8487048 18.53167,49.696073"
|
||||
id="path854-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c9a138;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="M 37.63247,8.4753024 37.436269,52.62038"
|
||||
id="path856-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#372c0f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 4.0627415,18.390392 14.7150265,6.474611 20.404836,-0.981002 18.639032,5.886011"
|
||||
id="path890"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#372c0f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 5.2974093,32.364138 14.5188257,6.670812 19.227634,-0.784802 17.26563,7.259413"
|
||||
id="path892"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#372c0f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 6.6299713,45.573855 20.908004,52.532318 39.550895,52.411814 56.057784,60.629029 58.547233,14.153933 39.859557,8.7712608 18.416343,9.7795792 3.081208,3.4042686 Z"
|
||||
id="path3763-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
216
icons/themed/Arch_CurtainWall_Tree.svg
Normal file
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="Arch_CurtainWall_Tree.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3794-8">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-5" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886"
|
||||
xlink:href="#linearGradient3794-8"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient3794-1">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-2" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886-0"
|
||||
xlink:href="#linearGradient3794-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3794"
|
||||
id="linearGradient3867-3"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="32.714748"
|
||||
y1="27.398352"
|
||||
x2="38.997726"
|
||||
y2="3.6523125"
|
||||
gradientTransform="matrix(-0.36199711,-0.85553613,0.73810354,-0.31230866,20.172664,63.335227)"
|
||||
spreadMethod="reflect" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.096831"
|
||||
inkscape:cx="53.636136"
|
||||
inkscape:cy="32.727474"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1360"
|
||||
inkscape:window-height="739"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2997"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wmayer]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Site</dc:title>
|
||||
<dc:date>2011-10-10</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Site.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="fill:#cdd6f4;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 6.6299713,45.573855 20.908004,52.532318 39.550895,52.411814 56.057784,60.629029 58.547233,14.153933 39.859557,8.7712607 18.416343,9.7795791 3.081208,3.4042685 Z"
|
||||
id="path3763"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 4.0627415,16.390392 14.7150265,6.474611 20.404836,-0.981002 18.639032,5.886011"
|
||||
id="path890-5"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 5.2974093,30.364138 14.5188257,6.670812 19.227634,-0.784802 17.26563,7.259413"
|
||||
id="path892-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="M 6.7565544,43.481706 21.277372,50.578904 38.047346,50.493083 54.4155,57.77384 56.62748,14.385588"
|
||||
id="path3763-7-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#232323;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="M 18.639033,9.8487048 20.601037,52.227979"
|
||||
id="path854"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#232323;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
d="M 39.63247,8.4753024 39.436269,52.62038"
|
||||
id="path856"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="M 16.639033,9.8487048 18.53167,49.696073"
|
||||
id="path854-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#585b70;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="M 37.63247,8.4753024 37.436269,52.62038"
|
||||
id="path856-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#232323;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 4.0627415,18.390392 14.7150265,6.474611 20.404836,-0.981002 18.639032,5.886011"
|
||||
id="path890"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#232323;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;font-variant-east_asian:normal"
|
||||
d="m 5.2974093,32.364138 14.5188257,6.670812 19.227634,-0.784802 17.26563,7.259413"
|
||||
id="path892"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#232323;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 6.6299713,45.573855 20.908004,52.532318 39.550895,52.411814 56.057784,60.629029 58.547233,14.153933 39.859557,8.7712608 18.416343,9.7795792 3.081208,3.4042686 Z"
|
||||
id="path3763-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
159
icons/themed/Arch_CutPlane.svg
Normal file
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2860"
|
||||
version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title1">Arch_CutPlane</title>
|
||||
<defs
|
||||
id="defs2862">
|
||||
<linearGradient
|
||||
id="linearGradient3">
|
||||
<stop
|
||||
style="stop-color:#89b4fa;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4" />
|
||||
<stop
|
||||
style="stop-color:#307bf7;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1">
|
||||
<stop
|
||||
style="stop-color:#307bf7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2" />
|
||||
<stop
|
||||
style="stop-color:#0846b3;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="156"
|
||||
y1="31.441406"
|
||||
x2="164"
|
||||
y2="56.558594"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-125,-7.0006774)" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3"
|
||||
id="linearGradient4"
|
||||
x1="126"
|
||||
y1="27.361328"
|
||||
x2="152"
|
||||
y2="59.638672"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-125,-7.0006774)" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2865">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[wood galaxy]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_CutPlane</dc:title>
|
||||
<dc:date>2014-11-11</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_CutPlane.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
id="rect1-3-7-1"
|
||||
style="fill:#56b4e9;stroke:#4c1313;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 47.00067,14.000078 57,15.666068" />
|
||||
<path
|
||||
id="rect1-3-2"
|
||||
style="fill:none;stroke:#4c1313;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 47,40.999667 57,37.666333 V 15.666367 l -10.000667,3.333555" />
|
||||
<path
|
||||
id="rect1-3-7-1-9"
|
||||
style="fill:#56b4e9;stroke:#89b4fa;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 47,14.000078 57,15.66689" />
|
||||
<path
|
||||
id="rect1-3-2-3"
|
||||
style="fill:none;stroke:#89b4fa;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 47,40.999667 57,37.666333 V 15.666589 l -10,3.333333" />
|
||||
<path
|
||||
id="rect1-2"
|
||||
style="fill:#d76363;fill-opacity:1;stroke:#4c1313;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 11,51.99968 36,6 V 12.000318 L 11,6.00032 v 10.999003 l 6,-2 24,4 v 26.000339 l -12,4 -18,-3.000001 z" />
|
||||
<path
|
||||
id="rect1-2-7"
|
||||
style="fill:none;fill-opacity:1;stroke:#f2cdcd;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;paint-order:stroke fill markers"
|
||||
d="m 13,46.332661 v 3.973659 l 32,5.332032 V 13.69368 L 13,8.3616479 v 7.9710081" />
|
||||
<path
|
||||
id="rect1"
|
||||
style="fill:url(#linearGradient4);stroke:#11111b;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 5,18.999323 24,4 v 26.000339 l -24,-4 z" />
|
||||
<path
|
||||
id="rect1-3"
|
||||
style="fill:url(#linearGradient2);stroke:#11111b;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 41,18.999323 -12,4 v 26.000339 l 12,-4 z" />
|
||||
<path
|
||||
id="rect1-3-7"
|
||||
style="fill:#89b4fa;fill-opacity:1;stroke:#11111b;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 5,18.999323 12,-4 24,4 -12,4 z" />
|
||||
<path
|
||||
id="path1"
|
||||
style="fill:none;stroke:#89b4fa;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 7,43.306303 20,3.332031 V 24.692682 L 7,21.360651 Z" />
|
||||
<path
|
||||
id="path1-0"
|
||||
style="fill:none;stroke:#307bf7;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 31,24.440729 v 21.785495 l 8,-2.667968 V 21.772761 Z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
220
icons/themed/Arch_Equipment.svg
Normal file
|
After Width: | Height: | Size: 21 KiB |
1132
icons/themed/Arch_Equipment_Clone.svg
Normal file
|
After Width: | Height: | Size: 41 KiB |
232
icons/themed/Arch_Equipment_Tree.svg
Normal file
|
After Width: | Height: | Size: 23 KiB |
218
icons/themed/Arch_Fence.svg
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Fence.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3794-8">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-5" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886"
|
||||
xlink:href="#linearGradient3794-8"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient3794-1">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-2" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886-0"
|
||||
xlink:href="#linearGradient3794-1"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.2080075"
|
||||
inkscape:cx="27.389555"
|
||||
inkscape:cy="21.184291"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2997"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Site_Tree</dc:title>
|
||||
<dc:date>2011-12-06</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g4538">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path931-5"
|
||||
d="M 3,43 H 61 V 35 H 3 Z"
|
||||
style="fill:#f8c459;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path933-8"
|
||||
d="m 5,37 v 4 h 54 v -4 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4534">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path931"
|
||||
d="M 3,57 H 61 V 49 H 3 Z"
|
||||
style="fill:#f8c459;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path933"
|
||||
d="m 5,51 v 4 h 54 v -4 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4518">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881"
|
||||
d="M 5,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#f8c459;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883"
|
||||
d="M 7,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4526">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881-4"
|
||||
d="M 49,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#f8c459;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883-5"
|
||||
d="M 51,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4522">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881-4-4"
|
||||
d="M 27,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#f8c459;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883-5-8"
|
||||
d="M 29,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
223
icons/themed/Arch_Fence_Tree.svg
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Fence_Tree.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
id="linearGradient3794">
|
||||
<stop
|
||||
style="stop-color:#6c7086;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3796" />
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3798" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3794-8">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-5" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886"
|
||||
xlink:href="#linearGradient3794-8"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient3794-1">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3796-2" />
|
||||
<stop
|
||||
style="stop-color:#ffea00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3798-2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="23.848686"
|
||||
x2="62.65237"
|
||||
y1="23.848686"
|
||||
x1="15.184971"
|
||||
gradientTransform="matrix(1.0265568,0,0,0.91490626,-3.236706,-1.8027032)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3886-0"
|
||||
xlink:href="#linearGradient3794-1"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.2080075"
|
||||
inkscape:cx="50.905069"
|
||||
inkscape:cy="22.363535"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2997"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Site_Tree</dc:title>
|
||||
<dc:date>2011-12-06</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
transform="translate(0,-12)"
|
||||
id="g937-3">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path931-5"
|
||||
d="M 3,55 H 61 V 47 H 3 Z"
|
||||
style="fill:#585b70;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path933-8"
|
||||
d="m 5,49 v 4 h 54 v -4 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#7f849c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g937"
|
||||
transform="translate(0,2)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path931"
|
||||
d="M 3,55 H 61 V 47 H 3 Z"
|
||||
style="fill:#585b70;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path933"
|
||||
d="m 5,49 v 4 h 54 v -4 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#7f849c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g887"
|
||||
transform="translate(2)">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881"
|
||||
d="M 3,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#585b70;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883"
|
||||
d="M 5,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#7f849c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(46)"
|
||||
id="g887-4">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881-4"
|
||||
d="M 3,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#585b70;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883-5"
|
||||
d="M 5,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#7f849c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(24)"
|
||||
id="g887-4-7">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881-4-4"
|
||||
d="M 3,61 V 27 l 5,-6 5,6 v 34 z"
|
||||
style="fill:#585b70;fill-rule:evenodd;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path883-5-8"
|
||||
d="M 5,59 V 28 l 3,-4 3,4 v 31 z"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#7f849c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.8 KiB |
111
icons/themed/Arch_Fixture.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
120
icons/themed/Arch_Floor.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
116
icons/themed/Arch_Floor_Tree.svg
Normal file
|
After Width: | Height: | Size: 15 KiB |
289
icons/themed/Arch_Frame.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
319
icons/themed/Arch_Frame_Tree.svg
Normal file
|
After Width: | Height: | Size: 38 KiB |
410
icons/themed/Arch_Grid.svg
Normal file
@@ -0,0 +1,410 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2985"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||
sodipodi:docname="Arch_Grid.svg">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3812">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3814" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3816" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3804">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3806" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3808" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3796">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3798" />
|
||||
<stop
|
||||
style="stop-color:#f8c459;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3800" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3883">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3793">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3793-2"
|
||||
id="linearGradient3799-8"
|
||||
x1="12.037806"
|
||||
y1="54.001419"
|
||||
x2="52.882648"
|
||||
y2="9.274148"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3793-2">
|
||||
<stop
|
||||
style="stop-color:#000f8a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3795-6" />
|
||||
<stop
|
||||
style="stop-color:#5190f8;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3797-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3883-6"
|
||||
id="linearGradient3889-4"
|
||||
x1="3"
|
||||
y1="31.671875"
|
||||
x2="59.25"
|
||||
y2="31.671875"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2727273,-0.18181818)" />
|
||||
<linearGradient
|
||||
id="linearGradient3883-6">
|
||||
<stop
|
||||
style="stop-color:#ffb400;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3885-4" />
|
||||
<stop
|
||||
style="stop-color:#ffe900;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3887-5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3796"
|
||||
id="linearGradient3802"
|
||||
x1="16.4375"
|
||||
y1="59.705883"
|
||||
x2="8.5625"
|
||||
y2="40.294117"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3804"
|
||||
id="linearGradient3810"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.5625"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3812"
|
||||
id="linearGradient3818"
|
||||
x1="16.4375"
|
||||
y1="58.411766"
|
||||
x2="8.562501"
|
||||
y2="41.588234"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="6.6796362"
|
||||
inkscape:cx="16.087193"
|
||||
inkscape:cy="23.330282"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2999"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[yorikvanhavre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Axis</dc:title>
|
||||
<dc:date>2011-12-12</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Axis.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040-9-1"
|
||||
width="57"
|
||||
height="6"
|
||||
x="4"
|
||||
y="9" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
|
||||
id="rect3044-8"
|
||||
width="6"
|
||||
height="56"
|
||||
x="9"
|
||||
y="5" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54,11 h 6"
|
||||
id="path3910-6-3-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3040-9"
|
||||
width="57"
|
||||
height="6"
|
||||
x="4"
|
||||
y="29" />
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3042-2"
|
||||
width="56"
|
||||
height="6"
|
||||
x="5"
|
||||
y="49" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-2"
|
||||
width="4"
|
||||
height="39"
|
||||
x="10"
|
||||
y="21" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
|
||||
id="rect3044-8-5"
|
||||
width="6"
|
||||
height="56"
|
||||
x="49"
|
||||
y="5" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5-7-4"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="10" />
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:1.92153788;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1"
|
||||
id="rect3044-8-2-4"
|
||||
width="6"
|
||||
height="12"
|
||||
x="29"
|
||||
y="49" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3042-3-5"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="50" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 7,51 h 4 V 35"
|
||||
id="path3904-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 11,60 V 52"
|
||||
id="path3906-7"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 32,51 H 60"
|
||||
id="path3910-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3044-7-2-4"
|
||||
width="4"
|
||||
height="39"
|
||||
x="50"
|
||||
y="21" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,60 V 52"
|
||||
id="path3906-7-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,52 V 32"
|
||||
id="path3906-7-9-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54,31 h 6"
|
||||
id="path3910-6-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:#664506;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.60000002;stroke-opacity:1;font-variant-east_asian:normal;opacity:1;vector-effect:none"
|
||||
id="rect3044-8-2"
|
||||
width="6"
|
||||
height="26"
|
||||
x="29"
|
||||
y="5" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5-7-5"
|
||||
width="39"
|
||||
height="4"
|
||||
x="5"
|
||||
y="10" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 5,11 H 50"
|
||||
id="path3908-3-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 5,31 h 6 V 6"
|
||||
id="path3902-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54,11 h 6"
|
||||
id="path3910-6-9-2"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none;stroke-width:0.5547002"
|
||||
id="rect3044-7-2-9"
|
||||
width="4"
|
||||
height="10"
|
||||
x="30"
|
||||
y="50" />
|
||||
<rect
|
||||
style="fill:#f8c459;fill-opacity:1;stroke:none"
|
||||
id="rect3040-5-7"
|
||||
width="39"
|
||||
height="4"
|
||||
x="21"
|
||||
y="30" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 51,32 V 6"
|
||||
id="path3906-7-9-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 34,31 H 50"
|
||||
id="path3908-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 14,31 H 31 V 6"
|
||||
id="path3902-8-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 15,51 H 33"
|
||||
id="path3904-9-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 31,60 V 52"
|
||||
id="path3906-7-8"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 54,31 h 6"
|
||||
id="path3910-6-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
128
icons/themed/Arch_Material.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
150
icons/themed/Arch_Material_Group.svg
Normal file
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="64px" height="64px" id="svg2816" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs id="defs2818">
|
||||
<linearGradient id="linearGradient4044">
|
||||
<stop style="stop-color:#11111b;stop-opacity:1" offset="0" id="stop4046" />
|
||||
<stop style="stop-color:#11111b;stop-opacity:0" offset="1" id="stop4048" />
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient3681">
|
||||
<stop id="stop3697" offset="0" style="stop-color:#f8cf78;stop-opacity:1" />
|
||||
<stop style="stop-color:#c35512;stop-opacity:1" offset="1" id="stop3685" />
|
||||
</linearGradient>
|
||||
<pattern patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)" id="pattern5231" xlink:href="#Strips1_1-4" />
|
||||
<pattern id="Strips1_1-4" patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)" height="1" width="2" patternUnits="userSpaceOnUse">
|
||||
<rect id="rect4483-4" height="2" width="1" y="-0.5" x="0" style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)" id="pattern5231-4" xlink:href="#Strips1_1-6" />
|
||||
<pattern id="Strips1_1-6" patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)" height="1" width="2" patternUnits="userSpaceOnUse">
|
||||
<rect id="rect4483-0" height="2" width="1" y="-0.5" x="0" style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)" id="pattern5296" xlink:href="#pattern5231-3" />
|
||||
<pattern patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)" id="pattern5231-3" xlink:href="#Strips1_1-4-3" />
|
||||
<pattern id="Strips1_1-4-3" patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)" height="1" width="2" patternUnits="userSpaceOnUse">
|
||||
<rect id="rect4483-4-6" height="2" width="1" y="-0.5" x="0" style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)" id="pattern5330" xlink:href="#Strips1_1-9" />
|
||||
<pattern id="Strips1_1-9" patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)" height="1" width="2" patternUnits="userSpaceOnUse">
|
||||
<rect id="rect4483-3" height="2" width="1" y="-0.5" x="0" style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<linearGradient xlink:href="#linearGradient3681" id="linearGradient3687" x1="37.89756" y1="41.087898" x2="4.0605712" y2="40.168594" gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient xlink:href="#linearGradient3681" id="linearGradient3695" x1="31.777767" y1="40.24213" x2="68.442062" y2="54.041203" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.25023482,-0.66040068,0.68751357,0.24036653,-8.7488565,43.149938)" />
|
||||
<radialGradient xlink:href="#linearGradient12512" id="radialGradient278" gradientUnits="userSpaceOnUse" cx="55" cy="125" fx="55" fy="125" r="14.375" />
|
||||
<linearGradient id="linearGradient12512">
|
||||
<stop style="stop-color:#cdd6f4;stop-opacity:1" offset="0.0000000" id="stop12513" />
|
||||
<stop style="stop-color:#f9d487;stop-opacity:0.89108908" offset="0.50000000" id="stop12517" />
|
||||
<stop style="stop-color:#f8ca69;stop-opacity:0" offset="1.0000000" id="stop12514" />
|
||||
</linearGradient>
|
||||
<radialGradient r="14.375" fy="125" fx="55" cy="125" cx="55" gradientUnits="userSpaceOnUse" id="radialGradient4017" xlink:href="#linearGradient12512" />
|
||||
<radialGradient xlink:href="#linearGradient12512-2" id="radialGradient278-5" gradientUnits="userSpaceOnUse" cx="55" cy="125" fx="55" fy="125" r="14.375" />
|
||||
<linearGradient id="linearGradient12512-2">
|
||||
<stop style="stop-color:#cdd6f4;stop-opacity:1" offset="0.0000000" id="stop12513-3" />
|
||||
<stop style="stop-color:#ffd820;stop-opacity:0.89108908" offset="0.5" id="stop12517-1" />
|
||||
<stop style="stop-color:#ff8000;stop-opacity:0" offset="1" id="stop12514-6" />
|
||||
</linearGradient>
|
||||
<linearGradient xlink:href="#linearGradient4044" id="linearGradient3060" gradientUnits="userSpaceOnUse" x1="15.78776" y1="50.394047" x2="27.641447" y2="39.95837" />
|
||||
<radialGradient xlink:href="#linearGradient12512-2" id="radialGradient3062" gradientUnits="userSpaceOnUse" cx="55" cy="125" fx="55" fy="125" r="14.375" />
|
||||
<linearGradient xlink:href="#linearGradient4044-2" id="linearGradient3060-5" gradientUnits="userSpaceOnUse" x1="15.78776" y1="50.394047" x2="27.641447" y2="39.95837" />
|
||||
<linearGradient id="linearGradient4044-2">
|
||||
<stop style="stop-color:#11111b;stop-opacity:1" offset="0" id="stop4046-5" />
|
||||
<stop style="stop-color:#11111b;stop-opacity:0" offset="1" id="stop4048-4" />
|
||||
</linearGradient>
|
||||
<radialGradient xlink:href="#linearGradient12512-2-7" id="radialGradient3062-5" gradientUnits="userSpaceOnUse" cx="55" cy="125" fx="55" fy="125" r="14.375" />
|
||||
<linearGradient id="linearGradient12512-2-7">
|
||||
<stop style="stop-color:#cdd6f4;stop-opacity:1" offset="0.0000000" id="stop12513-3-4" />
|
||||
<stop style="stop-color:#ffd820;stop-opacity:0.89108908" offset="0.5" id="stop12517-1-9" />
|
||||
<stop style="stop-color:#ff8000;stop-opacity:0" offset="1" id="stop12514-6-5" />
|
||||
</linearGradient>
|
||||
<radialGradient r="14.375" fy="125" fx="55" cy="125" cx="55" gradientUnits="userSpaceOnUse" id="radialGradient3086" xlink:href="#linearGradient12512-2-7" />
|
||||
<linearGradient xlink:href="#linearGradient4044-5" id="linearGradient3060-0" gradientUnits="userSpaceOnUse" x1="15.78776" y1="50.394047" x2="27.641447" y2="39.95837" />
|
||||
<linearGradient id="linearGradient4044-5">
|
||||
<stop style="stop-color:#11111b;stop-opacity:1" offset="0" id="stop4046-2" />
|
||||
<stop style="stop-color:#11111b;stop-opacity:0" offset="1" id="stop4048-9" />
|
||||
</linearGradient>
|
||||
<radialGradient xlink:href="#linearGradient12512-2-0" id="radialGradient3062-4" gradientUnits="userSpaceOnUse" cx="55" cy="125" fx="55" fy="125" r="14.375" />
|
||||
<linearGradient id="linearGradient12512-2-0">
|
||||
<stop style="stop-color:#cdd6f4;stop-opacity:1" offset="0.0000000" id="stop12513-3-7" />
|
||||
<stop style="stop-color:#ffd820;stop-opacity:0.89108908" offset="0.5" id="stop12517-1-1" />
|
||||
<stop style="stop-color:#ff8000;stop-opacity:0" offset="1" id="stop12514-6-57" />
|
||||
</linearGradient>
|
||||
<radialGradient r="14.375" fy="125" fx="55" cy="125" cx="55" gradientUnits="userSpaceOnUse" id="radialGradient3086-9" xlink:href="#linearGradient12512-2-0" />
|
||||
<linearGradient xlink:href="#linearGradient3960" id="linearGradient3966" x1="37.758171" y1="57.301327" x2="21.860462" y2="22.615412" gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient id="linearGradient3960">
|
||||
<stop style="stop-color:#bc8009;stop-opacity:1" offset="0" id="stop3962" />
|
||||
<stop style="stop-color:#f9e2af;stop-opacity:1" offset="1" id="stop3964" />
|
||||
</linearGradient>
|
||||
<filter color-interpolation-filters="sRGB" id="filter3980" x="-0.37450271" width="1.7490054" y="-0.37450271" height="1.7490054">
|
||||
<feGaussianBlur stdDeviation="4.4862304" id="feGaussianBlur3982" />
|
||||
</filter>
|
||||
<linearGradient y2="22.615412" x2="21.860462" y1="57.301327" x1="37.758171" gradientUnits="userSpaceOnUse" id="linearGradient4004" xlink:href="#linearGradient3960" />
|
||||
<linearGradient xlink:href="#linearGradient3960" id="linearGradient4041" gradientUnits="userSpaceOnUse" x1="37.758171" y1="57.301327" x2="21.860462" y2="22.615412" />
|
||||
<linearGradient xlink:href="#linearGradient3960-7" id="linearGradient4041-9" gradientUnits="userSpaceOnUse" x1="37.758171" y1="57.301327" x2="21.860462" y2="22.615412" />
|
||||
<linearGradient id="linearGradient3960-7">
|
||||
<stop style="stop-color:#bc8009;stop-opacity:1" offset="0" id="stop3962-1" />
|
||||
<stop style="stop-color:#f9e2af;stop-opacity:1" offset="1" id="stop3964-3" />
|
||||
</linearGradient>
|
||||
<filter color-interpolation-filters="sRGB" id="filter3980-1" x="-0.37450271" width="1.7490054" y="-0.37450271" height="1.7490054">
|
||||
<feGaussianBlur stdDeviation="4.4862304" id="feGaussianBlur3982-2" />
|
||||
</filter>
|
||||
<linearGradient xlink:href="#linearGradient3960-4" id="linearGradient4041-92" gradientUnits="userSpaceOnUse" x1="37.758171" y1="57.301327" x2="21.860462" y2="22.615412" />
|
||||
<linearGradient id="linearGradient3960-4">
|
||||
<stop style="stop-color:#bc8009;stop-opacity:1" offset="0" id="stop3962-4" />
|
||||
<stop style="stop-color:#f9e2af;stop-opacity:1" offset="1" id="stop3964-5" />
|
||||
</linearGradient>
|
||||
<filter color-interpolation-filters="sRGB" id="filter3980-9" x="-0.37450271" width="1.7490054" y="-0.37450271" height="1.7490054">
|
||||
<feGaussianBlur stdDeviation="4.4862304" id="feGaussianBlur3982-1" />
|
||||
</filter>
|
||||
</defs>
|
||||
<metadata id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Material_Group</dc:title>
|
||||
<dc:date>2015-04-19</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Material_Group.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="layer1">
|
||||
<g id="g4035" transform="translate(-56,-2)">
|
||||
<path transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-12" style="fill:url(#linearGradient4041);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)" d="m 69.375,125 c 0,7.93909 -6.435907,14.375 -14.375,14.375 -7.939093,0 -14.375,-6.43591 -14.375,-14.375 0,-7.93909 6.435907,-14.375 14.375,-14.375 7.939093,0 14.375,6.43591 14.375,14.375 z" id="path12511-77" style="color:#11111b;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;visibility:visible;display:block;filter:url(#filter3980)" />
|
||||
<path transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-0" style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-3" style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
</g>
|
||||
<g id="g4035-0" transform="translate(-80,19)">
|
||||
<path transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-12-6" style="fill:url(#linearGradient4041-9);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)" d="m 69.375,125 c 0,7.93909 -6.435907,14.375 -14.375,14.375 -7.939093,0 -14.375,-6.43591 -14.375,-14.375 0,-7.93909 6.435907,-14.375 14.375,-14.375 7.939093,0 14.375,6.43591 14.375,14.375 z" id="path12511-77-8" style="color:#11111b;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;visibility:visible;display:block;filter:url(#filter3980-1)" />
|
||||
<path transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-0-7" style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-3-4" style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
</g>
|
||||
<g id="g4035-2" transform="translate(-50,28)">
|
||||
<path transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-12-8" style="fill:url(#linearGradient4041-92);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)" d="m 69.375,125 c 0,7.93909 -6.435907,14.375 -14.375,14.375 -7.939093,0 -14.375,-6.43591 -14.375,-14.375 0,-7.93909 6.435907,-14.375 14.375,-14.375 7.939093,0 14.375,6.43591 14.375,14.375 z" id="path12511-77-9" style="color:#11111b;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;visibility:visible;display:block;filter:url(#filter3980-9)" />
|
||||
<path transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-0-6" style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
<path transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)" d="m 48.597521,39.95837 c 0,11.57372 -9.382354,20.956074 -20.956074,20.956074 -11.57372,0 -20.9560737,-9.382354 -20.9560737,-20.956074 0,-11.57372 9.3823537,-20.956074 20.9560737,-20.956074 11.57372,0 20.956074,9.382354 20.956074,20.956074 z" id="path4042-3-0" style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
857
icons/themed/Arch_Material_Multi.svg
Normal file
@@ -0,0 +1,857 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="Arch_Material_Multi.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4044">
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4046" />
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4048" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3681">
|
||||
<stop
|
||||
id="stop3697"
|
||||
offset="0"
|
||||
style="stop-color:#f8cf78;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#c35512;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3687"
|
||||
x1="37.89756"
|
||||
y1="41.087898"
|
||||
x2="4.0605712"
|
||||
y2="40.168594"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3695"
|
||||
x1="31.777767"
|
||||
y1="40.24213"
|
||||
x2="68.442062"
|
||||
y2="54.041203"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.25023482,-0.66040068,0.68751357,0.24036653,-8.7488565,43.149938)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12512"
|
||||
id="radialGradient278"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55"
|
||||
cy="125"
|
||||
fx="55"
|
||||
fy="125"
|
||||
r="14.375" />
|
||||
<linearGradient
|
||||
id="linearGradient12512">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop12513" />
|
||||
<stop
|
||||
style="stop-color:#f9d487;stop-opacity:0.89108908;"
|
||||
offset="0.50000000"
|
||||
id="stop12517" />
|
||||
<stop
|
||||
style="stop-color:#f8ca69;stop-opacity:0.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop12514" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="14.375"
|
||||
fy="125"
|
||||
fx="55"
|
||||
cy="125"
|
||||
cx="55"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4017"
|
||||
xlink:href="#linearGradient12512"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12512-2"
|
||||
id="radialGradient278-5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55"
|
||||
cy="125"
|
||||
fx="55"
|
||||
fy="125"
|
||||
r="14.375" />
|
||||
<linearGradient
|
||||
id="linearGradient12512-2">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop12513-3" />
|
||||
<stop
|
||||
style="stop-color:#ffd820;stop-opacity:0.89108908;"
|
||||
offset="0.5"
|
||||
id="stop12517-1" />
|
||||
<stop
|
||||
style="stop-color:#ff8000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop12514-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4044"
|
||||
id="linearGradient3060"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="15.78776"
|
||||
y1="50.394047"
|
||||
x2="27.641447"
|
||||
y2="39.95837" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12512-2"
|
||||
id="radialGradient3062"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55"
|
||||
cy="125"
|
||||
fx="55"
|
||||
fy="125"
|
||||
r="14.375" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4044-2"
|
||||
id="linearGradient3060-5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="15.78776"
|
||||
y1="50.394047"
|
||||
x2="27.641447"
|
||||
y2="39.95837" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4044-2">
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4046-5" />
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4048-4" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12512-2-7"
|
||||
id="radialGradient3062-5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55"
|
||||
cy="125"
|
||||
fx="55"
|
||||
fy="125"
|
||||
r="14.375" />
|
||||
<linearGradient
|
||||
id="linearGradient12512-2-7">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop12513-3-4" />
|
||||
<stop
|
||||
style="stop-color:#ffd820;stop-opacity:0.89108908;"
|
||||
offset="0.5"
|
||||
id="stop12517-1-9" />
|
||||
<stop
|
||||
style="stop-color:#ff8000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop12514-6-5" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="14.375"
|
||||
fy="125"
|
||||
fx="55"
|
||||
cy="125"
|
||||
cx="55"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3086"
|
||||
xlink:href="#linearGradient12512-2-7"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4044-5"
|
||||
id="linearGradient3060-0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="15.78776"
|
||||
y1="50.394047"
|
||||
x2="27.641447"
|
||||
y2="39.95837" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4044-5">
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4046-2" />
|
||||
<stop
|
||||
style="stop-color:#11111b;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4048-9" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12512-2-0"
|
||||
id="radialGradient3062-4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="55"
|
||||
cy="125"
|
||||
fx="55"
|
||||
fy="125"
|
||||
r="14.375" />
|
||||
<linearGradient
|
||||
id="linearGradient12512-2-0">
|
||||
<stop
|
||||
style="stop-color:#cdd6f4;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop12513-3-7" />
|
||||
<stop
|
||||
style="stop-color:#ffd820;stop-opacity:0.89108908;"
|
||||
offset="0.5"
|
||||
id="stop12517-1-1" />
|
||||
<stop
|
||||
style="stop-color:#ff8000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop12514-6-57" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="14.375"
|
||||
fy="125"
|
||||
fx="55"
|
||||
cy="125"
|
||||
cx="55"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3086-9"
|
||||
xlink:href="#linearGradient12512-2-0"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3960"
|
||||
id="linearGradient3966"
|
||||
x1="37.758171"
|
||||
y1="57.301327"
|
||||
x2="21.860462"
|
||||
y2="22.615412"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3960">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3962" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3964" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
inkscape:collect="always"
|
||||
id="filter3980"
|
||||
x="-0.29294133"
|
||||
width="1.5858827"
|
||||
y="-0.44242057"
|
||||
height="1.8848411">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="4.4862304"
|
||||
id="feGaussianBlur3982" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
y2="22.615412"
|
||||
x2="21.860462"
|
||||
y1="57.301327"
|
||||
x1="37.758171"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4004"
|
||||
xlink:href="#linearGradient3960"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3960"
|
||||
id="linearGradient4041"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="37.758171"
|
||||
y1="57.301327"
|
||||
x2="21.860462"
|
||||
y2="22.615412" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3960-7"
|
||||
id="linearGradient4041-9"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="37.758171"
|
||||
y1="57.301327"
|
||||
x2="21.860462"
|
||||
y2="22.615412" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3960-7">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3962-1" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3964-3" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
inkscape:collect="always"
|
||||
id="filter3980-1"
|
||||
x="-0.29294133"
|
||||
width="1.5858827"
|
||||
y="-0.44242057"
|
||||
height="1.8848411">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="4.4862304"
|
||||
id="feGaussianBlur3982-2" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3960-4"
|
||||
id="linearGradient4041-92"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="37.758171"
|
||||
y1="57.301327"
|
||||
x2="21.860462"
|
||||
y2="22.615412" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3960-4">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3962-4" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3964-5" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
inkscape:collect="always"
|
||||
id="filter3980-9"
|
||||
x="-0.29294133"
|
||||
width="1.5858827"
|
||||
y="-0.44242057"
|
||||
height="1.8848411">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="4.4862304"
|
||||
id="feGaussianBlur3982-1" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#cdd6f4"
|
||||
bordercolor="#38394b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="6.9457077"
|
||||
inkscape:cx="11.582505"
|
||||
inkscape:cy="34.410244"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4006"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Material_Group</dc:title>
|
||||
<dc:date>2015-04-19</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Material_Group.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g4035-0"
|
||||
transform="translate(-74,5)">
|
||||
<circle
|
||||
transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)"
|
||||
id="path4042-12-6"
|
||||
style="fill:url(#linearGradient4041-9);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
inkscape:export-ydpi="33.852203"
|
||||
inkscape:export-xdpi="33.852203"
|
||||
inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png"
|
||||
transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)"
|
||||
id="path12511-77-8"
|
||||
style="color:#11111b;display:block;visibility:visible;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;filter:url(#filter3980-1)"
|
||||
cx="55"
|
||||
cy="125"
|
||||
r="14.375" />
|
||||
<circle
|
||||
transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)"
|
||||
id="path4042-0-7"
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)"
|
||||
id="path4042-3-4"
|
||||
style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
</g>
|
||||
<g
|
||||
id="g4035"
|
||||
transform="translate(-65,13)">
|
||||
<circle
|
||||
transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)"
|
||||
id="path4042-12"
|
||||
style="fill:url(#linearGradient4041);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
inkscape:export-ydpi="33.852203"
|
||||
inkscape:export-xdpi="33.852203"
|
||||
inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png"
|
||||
transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)"
|
||||
id="path12511-77"
|
||||
style="color:#11111b;display:block;visibility:visible;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;filter:url(#filter3980)"
|
||||
cx="55"
|
||||
cy="125"
|
||||
r="14.375" />
|
||||
<circle
|
||||
transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)"
|
||||
id="path4042-0"
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)"
|
||||
id="path4042-3"
|
||||
style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
</g>
|
||||
<g
|
||||
id="g4035-2"
|
||||
transform="translate(-55,21)">
|
||||
<circle
|
||||
transform="matrix(0.6389479,0,0,0.63940352,79.151188,-6.6213323)"
|
||||
id="path4042-12-8"
|
||||
style="fill:url(#linearGradient4041-92);fill-opacity:1;stroke:#664506;stroke-width:3.12903023;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
inkscape:export-ydpi="33.852203"
|
||||
inkscape:export-xdpi="33.852203"
|
||||
inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png"
|
||||
transform="matrix(0.1255542,0.12343818,-0.19272145,0.17977458,109.1847,-15.260922)"
|
||||
id="path12511-77-9"
|
||||
style="color:#11111b;display:block;visibility:visible;fill:#cdd6f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;marker:none;filter:url(#filter3980-9)"
|
||||
cx="55"
|
||||
cy="125"
|
||||
r="14.375" />
|
||||
<circle
|
||||
transform="matrix(0.57262634,0,0,0.57262635,81.17178,-3.8812157)"
|
||||
id="path4042-0-6"
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:3.49267912;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
<circle
|
||||
transform="matrix(0.66806408,0,0,0.66806407,78.533742,-7.6947514)"
|
||||
id="path4042-3-0"
|
||||
style="fill:none;stroke:#664506;stroke-width:2.99372482;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
cx="27.641447"
|
||||
cy="39.95837"
|
||||
r="20.956074" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 28 KiB |
116
icons/themed/Arch_MergeWalls.svg
Normal file
|
After Width: | Height: | Size: 22 KiB |
122
icons/themed/Arch_MeshToShape.svg
Normal file
|
After Width: | Height: | Size: 14 KiB |
264
icons/themed/Arch_MultipleStructures.svg
Normal file
@@ -0,0 +1,264 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="svg2985"
|
||||
height="64px"
|
||||
width="64px">
|
||||
<defs
|
||||
id="defs2987">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="Arrow1Lstart"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="scale(0.8) translate(12.5,0)"
|
||||
style="fill-rule:evenodd;stroke:#89b4fa;stroke-width:1pt;stroke-opacity:1;fill:#89b4fa;fill-opacity:1"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
id="path4859" />
|
||||
</marker>
|
||||
<linearGradient
|
||||
id="linearGradient3850-6">
|
||||
<stop
|
||||
id="stop3852-2"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3854-9"
|
||||
offset="1"
|
||||
style="stop-color:#f8c459;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3858-2">
|
||||
<stop
|
||||
id="stop3860-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffc900;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3862-0"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="54.851124"
|
||||
x1="69.848015"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3972"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
y2="26.598274"
|
||||
x2="55.563385"
|
||||
y1="56.224525"
|
||||
x1="59.417618"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3974"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
y2="21.705095"
|
||||
x2="66.006668"
|
||||
y1="53"
|
||||
x1="69"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3986"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
y2="20.705095"
|
||||
x2="55.006672"
|
||||
y1="54"
|
||||
x1="57"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3988"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="51.449608"
|
||||
x1="69.018059"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3986-6"
|
||||
xlink:href="#linearGradient3850-6-1" />
|
||||
<linearGradient
|
||||
id="linearGradient3850-6-1">
|
||||
<stop
|
||||
id="stop3852-2-8"
|
||||
offset="0"
|
||||
style="stop-color:#bc8009;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3854-9-7"
|
||||
offset="1"
|
||||
style="stop-color:#f8c459;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="26.598274"
|
||||
x2="55.563385"
|
||||
y1="52.449608"
|
||||
x1="57.018063"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3988-9"
|
||||
xlink:href="#linearGradient3858-2-2" />
|
||||
<linearGradient
|
||||
id="linearGradient3858-2-2">
|
||||
<stop
|
||||
id="stop3860-7-0"
|
||||
offset="0"
|
||||
style="stop-color:#ffc900;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3862-0-2"
|
||||
offset="1"
|
||||
style="stop-color:#f9e2af;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="21.705095"
|
||||
x2="66.006668"
|
||||
y1="53"
|
||||
x1="69"
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4819"
|
||||
xlink:href="#linearGradient3850-6" />
|
||||
<linearGradient
|
||||
y2="20.705095"
|
||||
x2="55.006672"
|
||||
y1="54"
|
||||
x1="57"
|
||||
gradientTransform="matrix(-1,0,0,1,111.00667,0.294905)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient4821"
|
||||
xlink:href="#linearGradient3858-2" />
|
||||
<linearGradient
|
||||
y2="27.481174"
|
||||
x2="66.151985"
|
||||
y1="51.449608"
|
||||
x1="69.018059"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient5160"
|
||||
xlink:href="#linearGradient3850-6-1" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2990">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Antoine Lafr</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Structure</dc:title>
|
||||
<dc:date>2020-04-11</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_MultipleStructures.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<g
|
||||
transform="translate(2.010672,1.479651)"
|
||||
id="g4817">
|
||||
<path
|
||||
id="path3927-5-6"
|
||||
style="color:#11111b;visibility:visible;fill:url(#linearGradient4819);fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
|
||||
d="m 50,24 0.0067,35.294905 -10,-4 V 24 c 0,-5 -4.017372,-11.479651 -7.017372,-14.479651 L 40.0067,2.294905 C 46.0067,7.294905 50,16 50,24 Z" />
|
||||
<path
|
||||
id="path3929-3-0"
|
||||
style="color:#11111b;visibility:visible;fill:url(#linearGradient4821);fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
|
||||
d="m 59.0067,20.520349 c -0.01737,-5.479651 -4.017372,-16 -10.017372,-19 L 40.0067,2.294905 C 45.0067,6.294905 50,16 50,24 l 0.0067,35.294905 9,-4 z" />
|
||||
<path
|
||||
id="path3846-6"
|
||||
d="m 57.0067,21.294905 v 32.539551 l -5.00003,2.460449 3e-5,-33 z"
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3848-2"
|
||||
d="m 48,24 -5.9933,-2 v 32 l 5.982628,2.520349 z"
|
||||
style="fill:none;stroke:#f8c459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,61.006671,2.294905)"
|
||||
id="g3978-3">
|
||||
<g
|
||||
transform="translate(-22,2)"
|
||||
id="g3866-9-7">
|
||||
<g
|
||||
transform="translate(2.006671,-0.294905)"
|
||||
id="g5158">
|
||||
<path
|
||||
id="path3925-7-3-5"
|
||||
style="color:#11111b;visibility:visible;fill:#f9e2af;fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 52,23 9,2 9,-2 -8,-2 z" />
|
||||
<path
|
||||
id="path3927-5-6-9"
|
||||
style="color:#11111b;visibility:visible;fill:url(#linearGradient5160);fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 61,25 v 32 l 9,-4 V 23 Z" />
|
||||
<path
|
||||
id="path3929-3-0-2"
|
||||
style="color:#11111b;visibility:visible;fill:url(#linearGradient3988-9);fill-opacity:1;fill-rule:evenodd;stroke:#664506;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
|
||||
d="m 52,23 9,2 v 32 l -9,-4 z" />
|
||||
<path
|
||||
id="path3846-6-2"
|
||||
d="M 54,26 V 51.539551 L 59,54 V 27 Z"
|
||||
style="fill:none;stroke:#f9e2af;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3848-2-8"
|
||||
d="m 63,27 5,-1.550391 v 26.255486 l -4.982658,2.520349 z"
|
||||
style="fill:none;stroke:#f8c459;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,4)"
|
||||
id="g5168">
|
||||
<path
|
||||
style="fill:#00ffff;stroke:#052459;stroke-width:6;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 5,52 V 23"
|
||||
id="path3878-4" />
|
||||
<path
|
||||
style="fill:#00ffff;stroke:#89b4fa;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 5,52 V 22"
|
||||
id="path3878" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(2)"
|
||||
id="g5172">
|
||||
<path
|
||||
style="fill:none;stroke:#052459;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 34,56 V 25 c 0,-3 -5,-9 -8,-12"
|
||||
id="path3878-2-8" />
|
||||
<path
|
||||
style="fill:none;stroke:#89b4fa;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 8;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 34,56 V 25 c 0,-3 -5,-9 -8,-12"
|
||||
id="path3878-2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
680
icons/themed/Arch_Nest.svg
Normal file
|
After Width: | Height: | Size: 25 KiB |
68
icons/themed/Arch_Panel.svg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
572
icons/themed/Arch_Panel_Clone.svg
Normal file
|
After Width: | Height: | Size: 27 KiB |
70
icons/themed/Arch_Panel_Cut.svg
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
128
icons/themed/Arch_Panel_Sheet.svg
Normal file
|
After Width: | Height: | Size: 18 KiB |
234
icons/themed/Arch_Panel_Sheet_Tree.svg
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient3633">
|
||||
<stop
|
||||
style="stop-color:#fff652;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3635" />
|
||||
<stop
|
||||
style="stop-color:#ffbf00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3637" />
|
||||
</linearGradient>
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4" />
|
||||
<pattern
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:#0b0b0b;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6" />
|
||||
<pattern
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:#0b0b0b;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3" />
|
||||
<pattern
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:#0b0b0b;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9" />
|
||||
<pattern
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:#0b0b0b;stroke:none" />
|
||||
</pattern>
|
||||
<linearGradient
|
||||
y2="9"
|
||||
x2="24"
|
||||
y1="64"
|
||||
x1="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3120"
|
||||
xlink:href="#linearGradient3071" />
|
||||
<linearGradient
|
||||
id="linearGradient3071">
|
||||
<stop
|
||||
id="stop3073"
|
||||
offset="0"
|
||||
style="stop-color:#bdbdbd;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3075"
|
||||
offset="1"
|
||||
style="stop-color:#cdd6f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3874"
|
||||
id="linearGradient3880"
|
||||
x1="56"
|
||||
y1="47"
|
||||
x2="53"
|
||||
y2="39"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3874">
|
||||
<stop
|
||||
style="stop-color:#bdbdbd;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3876" />
|
||||
<stop
|
||||
style="stop-color:#f1f1f1;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3878" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="9"
|
||||
x2="24"
|
||||
y1="64"
|
||||
x1="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3075"
|
||||
xlink:href="#linearGradient3071" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3765"
|
||||
id="linearGradient3771"
|
||||
x1="40"
|
||||
y1="68"
|
||||
x2="34"
|
||||
y2="12"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(147,-3)" />
|
||||
<linearGradient
|
||||
id="linearGradient3765">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3767" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3769" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Yorik van Havre]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Arch_Panel_Sheet_Tree</dc:title>
|
||||
<dc:date>2016-12-17</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Arch/Resources/icons/Arch_Panel_Sheet_Tree.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 2.9999999,9 0,44 L 51,53 61,43 61,9 z"
|
||||
id="rect3005"
|
||||
style="color:#11111b;fill:url(#linearGradient3075);fill-opacity:1;fill-rule:evenodd;stroke:#313131;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 4.9999999,51 0,-40 L 59,11 l 0,32 -6,8 z"
|
||||
id="path3096" />
|
||||
<path
|
||||
d="m 61,43 c 0,-1 -4,-4 -8,-4 0,0 2,10 -2,14 z"
|
||||
id="path3778"
|
||||
style="color:#11111b;fill:url(#linearGradient3880);fill-opacity:1;fill-rule:evenodd;stroke:#4e4e4e;stroke-width:1.95121026;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="fill:none;stroke:#bdbdbd;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 53.08551,48.1244 6.65843,-6.453618"
|
||||
id="path3125" />
|
||||
<path
|
||||
d="m 61,43 c 0,-1 -4,-4 -8,-4 0,0 2,10 -2,14 z"
|
||||
id="path3778-3"
|
||||
style="color:#11111b;fill:none;stroke:#313131;stroke-width:1.95121026;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="color:#11111b;fill:#313131;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 6,12 0,38 16,0 0,-6 6,0 0,6 16,0 0,-38 -16,0 0,6 -6,0 0,-6 z m 4,4 8,0 0,2 c 0,3 1,4 4,4 l 6,0 c 3,0 4,-1 4,-4 l 0,-2 8,0 0,30 -8,0 0,-2 c 0,-3 -1,-4 -4,-4 l -6,0 c -3,0 -4,1 -4,3 l 0,3 -8,0 z"
|
||||
id="path4207" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
68
icons/themed/Arch_Panel_Tree.svg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
96
icons/themed/Arch_Pipe.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
106
icons/themed/Arch_PipeConnector.svg
Normal file
|
After Width: | Height: | Size: 12 KiB |
96
icons/themed/Arch_Pipe_Tree.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
477
icons/themed/Arch_Profile.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
423
icons/themed/Arch_Project.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
435
icons/themed/Arch_Project_Tree.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
169
icons/themed/Arch_Rebar.svg
Normal file
|
After Width: | Height: | Size: 21 KiB |
169
icons/themed/Arch_Rebar_Tree.svg
Normal file
|
After Width: | Height: | Size: 21 KiB |
182
icons/themed/Arch_Reference.svg
Normal file
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg249"
|
||||
version="1.1"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
id="linearGradient1">
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3815">
|
||||
<stop
|
||||
id="stop3817"
|
||||
offset="0"
|
||||
style="stop-color:#6c7086;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3819"
|
||||
offset="1"
|
||||
style="stop-color:#cdd6f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3815"
|
||||
id="linearGradient3771"
|
||||
x1="98"
|
||||
y1="1047.3622"
|
||||
x2="81"
|
||||
y2="993.36218"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-60,-988.36218)" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(0,-4)"
|
||||
xlink:href="#linearGradient3777"
|
||||
id="linearGradient3783"
|
||||
x1="64.244514"
|
||||
y1="51.048775"
|
||||
x2="39.166134"
|
||||
y2="22.474567"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3777">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3779" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3781" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(0,-4)"
|
||||
xlink:href="#linearGradient3767"
|
||||
id="linearGradient3773"
|
||||
x1="39.166134"
|
||||
y1="61.764099"
|
||||
x2="3.3382015"
|
||||
y2="15.331016"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3767">
|
||||
<stop
|
||||
style="stop-color:#bc8009;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3769" />
|
||||
<stop
|
||||
style="stop-color:#f9e2af;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3771" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="3.3382015"
|
||||
y1="11.331016"
|
||||
x2="64.244514"
|
||||
y2="7.7592402"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
style="display:inline">
|
||||
<path
|
||||
style="display:inline;fill:url(#linearGradient3771);fill-opacity:1;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="m 11,3 v 58.00002 h 42 v -48 L 43,3 Z"
|
||||
id="path2991" />
|
||||
<path
|
||||
style="display:inline;fill:none;stroke:#cdd6f4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 13,5 V 59.00002 H 51 V 13.81392 L 41.99741,5 Z"
|
||||
id="path3763" />
|
||||
<path
|
||||
style="display:inline;fill:#1e1e2e;fill-opacity:0.392157;stroke:#1e1e2e;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 43,3 V 13.00002 H 53 Z"
|
||||
id="path2993" />
|
||||
</g>
|
||||
<g
|
||||
id="layer3"
|
||||
style="display:inline"
|
||||
transform="translate(0,1.9995285)">
|
||||
<g
|
||||
id="layer1-3"
|
||||
transform="matrix(0.55823442,0,0,0.55994556,13.136501,14.655248)"
|
||||
style="display:inline;stroke-width:3.57725;stroke-dasharray:none">
|
||||
<path
|
||||
style="fill:url(#linearGradient2);stroke:#333333;stroke-width:3.57725;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3.3382015,11.331016 39.166134,18.474567 64.244514,7.75924 28.416933,0.61568843 Z"
|
||||
id="path2993-0" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3783);fill-opacity:1;stroke:#333333;stroke-width:3.57725;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 64.244514,7.75924 V 47.048774 L 39.166134,57.764101 V 18.474567 Z"
|
||||
id="path2995" />
|
||||
<path
|
||||
id="path3825"
|
||||
d="M 3.3382015,11.331016 39.166134,18.474567 V 57.764101 L 3.3382015,50.62055 Z"
|
||||
style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3773);fill-opacity:1;fill-rule:evenodd;stroke:#333333;stroke-width:3.57725;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
</g>
|
||||
<path
|
||||
id="path3825-6"
|
||||
style="display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f8e549;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="m 17,41.359375 c 5.333333,1.067708 10.666667,2.135417 16,3.203125 0,-5.973958 0,-11.947917 0,-17.921875 -5.333333,-1.067708 -10.666667,-2.135417 -16,-3.203125 0,5.973958 0,11.947917 0,17.921875 z" />
|
||||
<path
|
||||
id="path1"
|
||||
style="fill:none;fill-opacity:1;stroke:#f8e549;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 37,26.320312 c 0,5.881511 0,11.763021 0,17.644532 3.333333,-1.428386 6.666667,-2.856771 10,-4.285156 0,-5.881511 0,-11.763021 0,-17.644532 -3.333333,1.428386 -6.666667,2.856771 -10,4.285156 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
71
icons/themed/Arch_Remove.svg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
85
icons/themed/Arch_RemoveShape.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
106
icons/themed/Arch_Roof.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
106
icons/themed/Arch_Roof_Tree.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
68
icons/themed/Arch_Schedule.svg
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
67
icons/themed/Arch_SectionPlane.svg
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
56
icons/themed/Arch_SectionPlane_Tree.svg
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
77
icons/themed/Arch_SelectNonManifold.svg
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
71
icons/themed/Arch_Site.svg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
71
icons/themed/Arch_Site_Tree.svg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
114
icons/themed/Arch_Space.svg
Normal file
|
After Width: | Height: | Size: 16 KiB |
737
icons/themed/Arch_Space_Clone.svg
Normal file
|
After Width: | Height: | Size: 34 KiB |