Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1 align="center">SeEx (Seek and Export)</h1>

<p align="center">
<strong>Batch export LCSC components in formats supported by Altium Designer (AD) and KiCad.</strong>
<strong>Batch export LCSC components in formats supported by Altium Designer (AD), KiCad and Cadence (OrCAD Capture / Allegro).</strong>
</p>

<p align="center"><a href="README.en.md">English</a> | <a href="README.md">简体中文</a></p>
Expand Down Expand Up @@ -38,13 +38,22 @@ The project history, in chronological order:
- [x] Support batch export.
- [x] Export multiple components into one merged `schlib` and `pcblib` library.

### Cadence (OrCAD Capture / Allegro)

- [x] Export `Capture` schematic symbols as one `Library XML` file, which Capture turns into an `.olb` with `File > Import > Library XML`.
- [x] Export `Allegro` footprints as one `SKILL` script per footprint plus a library script: running `skill load("<library>_allegro/<library>.il")` in the Allegro PCB Editor command window builds the `.dra`, `.psm` and `.pad` files in that folder.
- [x] Export `3D` models (`step`), mapped on the footprints where EasyEDA places them.
- [x] Standard packages (chip resistors and capacitors, `SOT`, `SOD`, `SOIC`, `QFN`, ...) get `IPC-7352` lands, checked against the manufacturer's; other packages keep the manufacturer's lands with `IPC-7352` silkscreen, assembly and place-bound rules.
- [x] `seex` runs no Cadence program itself; the import is done in Cadence.

### Shared Features

- [x] Export metadata in Chinese or English.
- [x] Use multiple threads for downloads.
- [x] Add new components to existing libraries exported by `seex`.
- [x] Customize schematic stroke and fill colors.
- [x] Export `3D` models independently.
- [x] Remove the EasyEDA logo (watermark) from `3D` models by default and rebuild them; a model the logo cannot be removed from safely is exported as it is and named in the export result.

## Supported EDA Versions

Expand All @@ -53,13 +62,14 @@ The project history, in chronological order:

- [x] `KiCad 9.0` to `Latest`
- [x] `Altium Designer 23.x` to `Latest`
- [x] `Cadence SPB 26.1` (OrCAD X Capture / Allegro X); the Allegro footprint scripts need a release that runs `SKILL` (`Allegro PCB Designer` or `OrCAD PCB Designer Professional`)

## What Is Planned?

- [ ] Support more `EDA` tools, such as `allegro` and `pads`.
- [ ] Support more `EDA` tools, such as `pads`.
- [ ] Continue improving the current workflow and fix more hidden `bugs`.
- [ ] Keep improving interactions and usability, refine the icons, and try new design languages.
- [ ] Explore a broadly applicable way to remove or hide parts of `3D` models, such as specific markings.
- [ ] Explore a broadly applicable way to remove or hide parts of `3D` models, such as specific markings (the EasyEDA logo is already removed by default).

## Who Would SeEx Like to Contribute?

Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1 align="center">SeEx(Seek and Export)</h1>

<p align="center">
<strong>批量导出立创商城元件为Altium Designer(AD)、KiCad可用的格式。</strong>
<strong>批量导出立创商城元件为Altium Designer(AD)、KiCad、Cadence(OrCAD Capture / Allegro)可用的格式。</strong>
</p>

<p align="center"><a href="README.en.md">English</a> | <a href="README.md">简体中文</a></p>
Expand All @@ -32,24 +32,32 @@
- [x] 可以单独导出器件的`schlib`, `pcblib`(`pcblib`已经内嵌了`step`模型)。
- [x] 也可以批量导出。
- [x] 支持导出多个器件到同一个`schlib`, `pcblib`,即合并导出。
### Cadence(OrCAD Capture / Allegro)部分
- [x] 导出`Capture`原理图符号:一个`Library XML`文件,在`Capture`中通过`File > Import > Library XML`转换为`.olb`。
- [x] 导出`Allegro`封装:每个封装一个`SKILL`脚本,外加一个库脚本;在`Allegro PCB Editor`的命令窗口执行`skill load("<库>_allegro/<库>.il")`,即在同一目录生成`.dra`、`.psm`和`.pad`。
- [x] 导出`3D`模型(`step`),封装中已按立创EDA的位置映射好模型。
- [x] 标准封装(贴片阻容、`SOT`、`SOD`、`SOIC`、`QFN`等)按`IPC-7352`计算焊盘并核对厂家焊盘;其余封装保留厂家焊盘,按`IPC-7352`规则生成丝印、装配层和占位区。
- [x] `seex`本身不调用任何`Cadence`程序,导入由用户在`Cadence`中完成。
### 共同部分
- [x] 均支持选择中英文元数据导出。
- [x] 均支持多线程下载。
- [x] 均支持向已现存的经由`seex`导出的库里添加新的器件/元件。
- [x] 均支持自定义原理图的描边和填充颜色。
- [x] 均支持单独导出`3D`模型。
- [x] 默认去除`3D`模型上的立创EDA标志(水印),重建模型;无法安全去除时保留原模型,并在导出结果中列出这些元件。

## SeEx支持的`EDA`版本???
> [!NOTE]
> 这些版本仅为目前所知,不排除`seex`支持更多的版本。如果您无法在更低版本的`EDA`软件中打开`seex`导出的库,可以在`issue`里提出,会考虑适配。
- [x] `KiCad 9.0` ~ `Latest`
- [x] `Altium Designer 23.x` ~ `Latest`
- [x] `Cadence SPB 26.1`(OrCAD X Capture / Allegro X);`Allegro`封装脚本需要支持`SKILL`的版本(`Allegro PCB Designer`或`OrCAD PCB Designer Professional`)

## SeEx未来想做啥???
- [ ] 支持更多的`EDA`工具,类似`allegro`, `pads`等。
- [ ] 支持更多的`EDA`工具,类似`pads`等。
- [ ] 继续完善现在的工作流,修复更多隐藏的`bug`。
- [ ] 持续优化交互功能,提升用户使用体验,优化图标,尝试新的设计语言。
- [ ] 探索一种普遍适用的方案,用于除去/隐去`3D`模型的一部分组件,类似特定标识符等等。
- [ ] 探索一种普遍适用的方案,用于除去/隐去`3D`模型的一部分组件(立创EDA标志已默认去除),类似特定标识符等等。

## SeEx期待的贡献者???
- [x] 具有软件设计经验,能持续维护软件。
Expand Down
21 changes: 18 additions & 3 deletions src/altium/workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::error::{AppError, Result};
use crate::lceda::{LcedaClient, SearchItem};
use crate::lcsc::{LcscClient, LcscProduct};
use crate::metadata::ResolvedMetadata;
use crate::step_model::ModelCleanup;
use crate::util::{nested_string, sanitize_filename, split_obj_and_mtl};

#[derive(Debug, Serialize)]
Expand All @@ -38,6 +39,7 @@ pub async fn download_step(
item: &SearchItem,
out_dir: &Path,
force: bool,
models: &ModelCleanup,
) -> Result<PathBuf> {
fs::create_dir_all(out_dir)?;
let out_file = out_dir.join(item.choose_step_filename());
Expand All @@ -47,6 +49,10 @@ pub async fn download_step(

let model_uuid = client.get_model_uuid(item).await?;
let content = client.download_step_bytes(&model_uuid).await?;
let label = item
.lcsc_id()
.unwrap_or_else(|| item.display_name().to_string());
let content = models.clean(&label, &content);
// The STEP is stored in LCEDA's own frame, which does not always rest on the board plane.
fs::write(&out_file, crate::step_model::place_step_on_board(&content))?;
Ok(out_file)
Expand Down Expand Up @@ -184,6 +190,7 @@ pub(crate) async fn load_placed_step_for_pcblib(
client: &LcedaClient,
item: &SearchItem,
model_candidates: &[String],
models: &ModelCleanup,
) -> Option<ModelData> {
let mut candidates = model_candidates.to_vec();
if item.model_uuid.is_some() {
Expand Down Expand Up @@ -223,6 +230,10 @@ pub(crate) async fn load_placed_step_for_pcblib(
}
};
let _ = fs::remove_file(&downloaded);
let label = item
.lcsc_id()
.unwrap_or_else(|| item.display_name().to_string());
let bytes = models.clean(&label, &bytes);

let placed = scratch_step_path();
let written = fs::File::create(&placed)
Expand Down Expand Up @@ -250,9 +261,10 @@ pub(crate) async fn build_pcblib_library_from_detail(
item: &SearchItem,
footprint_data: &Value,
component_name: &str,
models: &ModelCleanup,
) -> Result<PcbLibrary> {
let candidates = step_model_candidates(item, footprint_data);
let step_data = load_placed_step_for_pcblib(client, item, &candidates).await;
let step_data = load_placed_step_for_pcblib(client, item, &candidates, models).await;
build_pcblib_from_payload_with_model(footprint_data, component_name, step_data)
}

Expand Down Expand Up @@ -306,12 +318,13 @@ pub async fn build_pcblib_library_for_item(
client: &LcedaClient,
item: &SearchItem,
footprint_name: &str,
models: &ModelCleanup,
) -> Result<PcbLibrary> {
let footprint_uuid = item
.footprint_uuid()
.ok_or(AppError::MissingSymbolOrFootprint)?;
let footprint_data = client.component_detail(&footprint_uuid).await?;
build_pcblib_library_from_detail(client, item, &footprint_data, footprint_name).await
build_pcblib_library_from_detail(client, item, &footprint_data, footprint_name, models).await
}

pub async fn build_schlib_component_for_item(
Expand Down Expand Up @@ -358,6 +371,7 @@ pub async fn export_pcblib(
item: &SearchItem,
out_dir: &Path,
force: bool,
models: &ModelCleanup,
) -> Result<PathBuf> {
fs::create_dir_all(out_dir)?;
let footprint_uuid = item
Expand All @@ -371,7 +385,8 @@ pub async fn export_pcblib(
}

let library =
build_pcblib_library_from_detail(client, item, &footprint_data, &footprint_name).await?;
build_pcblib_library_from_detail(client, item, &footprint_data, &footprint_name, models)
.await?;
write_pcblib(&library, &out_file)?;
Ok(out_file)
}
Expand Down
13 changes: 11 additions & 2 deletions src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::error::{AppError, Result};
use crate::lceda::{LcedaClient, SearchItem};
use crate::lcsc::{LcscClient, LcscProduct};
use crate::monitor::ExportProgressCallback;
use crate::step_model::ModelCleanup;
use crate::util::sanitize_filename;

#[derive(Clone)]
Expand All @@ -44,6 +45,8 @@ pub struct BatchOptions {
pub schematic_stroke_color: [u8; 3],
/// `None` exports the symbol body with no fill at all.
pub schematic_fill_color: Option<[u8; 3]>,
/// What happens to downloaded 3D models before they are embedded (logo removal).
pub models: Arc<ModelCleanup>,
pub progress: Option<ExportProgressCallback>,
}

Expand Down Expand Up @@ -871,6 +874,7 @@ async fn export_merged_components_parallel(
merged_pcblib_file,
options.schematic_stroke_color,
options.schematic_fill_color,
&options.models,
parallel,
options.append,
summary,
Expand Down Expand Up @@ -1018,6 +1022,7 @@ async fn build_merged_components_parallel(
merged_pcblib_file: &str,
schematic_stroke_color: [u8; 3],
schematic_fill_color: Option<[u8; 3]>,
models: &Arc<ModelCleanup>,
parallel: usize,
as_records: bool,
summary: &mut BatchSummary,
Expand All @@ -1032,6 +1037,7 @@ async fn build_merged_components_parallel(
let client = client.clone();
let semaphore = semaphore.clone();
let merged_pcblib_file = merged_pcblib_file.clone();
let models = Arc::clone(models);
join_set.spawn(async move {
let _permit = semaphore
.acquire_owned()
Expand All @@ -1045,6 +1051,7 @@ async fn build_merged_components_parallel(
merged_pcblib_file.as_str(),
schematic_stroke_color,
schematic_fill_color,
&models,
)
.await;
// An append merge only needs the streams, and reducing the part here keeps
Expand Down Expand Up @@ -1095,6 +1102,7 @@ async fn build_named_merged_component(
merged_pcblib_file: &str,
schematic_stroke_color: [u8; 3],
schematic_fill_color: Option<[u8; 3]>,
models: &ModelCleanup,
) -> Result<IndexedMergeArtifacts> {
let schlib_record = if targets.schlib {
let symbol_data = named
Expand Down Expand Up @@ -1122,7 +1130,7 @@ async fn build_named_merged_component(
// only needed to build the footprint, and a download takes seconds while the
// batch has one in flight per parallel part.
let step_data =
load_placed_step_for_pcblib(client, &named.item, &named.step_candidates).await;
load_placed_step_for_pcblib(client, &named.item, &named.step_candidates, models).await;
let footprint_data = named
.footprint_data
.as_ref()
Expand Down Expand Up @@ -1342,7 +1350,7 @@ async fn export_component(

if targets.pcblib {
let pcblib_dir = options.output.join("pcblib");
export_pcblib(client, &item, &pcblib_dir, options.force).await?;
export_pcblib(client, &item, &pcblib_dir, options.force, &options.models).await?;
}

Ok(ExportedComponent { display_name })
Expand Down Expand Up @@ -1485,6 +1493,7 @@ mod tests {
force: false,
schematic_stroke_color: [11, 56, 104],
schematic_fill_color: Some([255, 255, 224]),
models: Default::default(),
progress: None,
};

Expand Down
Loading