> [Site index](https://perfectvector.com/llms.txt) — available pages and descriptions.

# Tô gạch SVG: tạo đường dẫn thật cho máy vẽ bút

> Tạo đường gạch mở thực từ vùng SVG kín. Tái tạo kiểm tra lỗ, khoảng cách, góc và tệp đã lưu bằng ví dụ Paper.js tự tạo.

Source: https://perfectvector.com/vi/blog/hatch-fill-svg-pen-paths

Language: vi
Author: Irene Kim
Published: 2026-10-11T08:00:00+09:00
Updated: 2026-10-11T08:00:00+09:00

Để tô gạch SVG cho máy vẽ bút, hãy tạo các đường mở trong vùng kín mong muốn, chia chúng tại ranh giới và xuất các đoạn còn lại thành hình học. Kiểm tra tệp đã lưu để tìm lộ trình qua lỗ hoặc ngoài hình trước khi chuẩn bị công việc máy.

Màu tô hoặc bản xem trước có sọc tự nó không cung cấp các lộ trình vẽ đó. Hướng dẫn này dựng biểu trưng năm cạnh tự tạo với lỗ chữ nhật, dùng Paper.js lấy phần giao của đường mở với vùng đó và mở lại SVG đã lưu để kiểm tra. Các kiểm tra xác nhận hình học đường tâm kỹ thuật số, không phải vẽ vật lý thành công.

## 1. Chọn vùng để tô, không phải đường để khôi phục

Bạn cần vùng kín có lỗ là một phần hình học. Hình chữ nhật trắng đặt trên hình đặc có thể trông như lỗ nhưng vẫn để vùng bên dưới nguyên vẹn. [Tài liệu tô gạch GRBL-Plotter](https://grbl-plotter.de/index.php?id=hatch-fill) minh họa khác biệt này bằng đối tượng chồng lấn so với lỗ bên trong một đường dẫn. Chúng tôi không chạy GRBL-Plotter ở đây.

Nếu muốn khôi phục một nét giữa đường raster dày, dùng [hướng dẫn SVG một nét](https://perfectvector.com/vi/blog/drawing-to-single-line-svg). Tô gạch tạo nhiều nét chạy qua vùng; không khôi phục đường tâm bút gốc.

Giữ bản sao thiết kế có tô. Ví dụ chủ ý tạo lộ trình gạch mà không thêm lượt đường bao. Nếu muốn vẽ cả ranh giới ngoài hoặc ranh giới lỗ, hãy chuẩn bị chúng thành lộ trình riêng có chủ đích.

## 2. Phân biệt hình thức bị cắt hiển thị với đường đã cắt ngắn

[Họa tiết SVG](https://www.w3.org/TR/SVG2/pservers.html#Patterns) tô một ô lặp. [Đường cắt hiển thị](https://www.w3.org/TR/css-masking-1/#ClippingPaths) giới hạn vùng kết xuất mà không đổi hình học gốc. Cả hai có thể tạo ảnh màn hình hữu ích, nhưng ứng dụng vẫn cần cách biến hình thức đó thành lộ trình bút.

Bản đối chứng chỉ cắt hiển thị lưu mười đường ngang, mỗi đường dài 200 đơn vị người dùng. Phép cắt giấu phần ngoài và lỗ chữ nhật. Tổng chiều dài đường đã lưu vẫn là 2.000 đơn vị.

Bản xuất thưa đã cắt ngắn chứa 14 đường dẫn mở riêng, tổng 1.320 đơn vị. Nó không có đường cắt hiển thị, họa tiết, mặt nạ, ảnh nhúng hay biểu tượng tái sử dụng. Bốn hàng gạch chia thành hai đường quanh lỗ. Khác biệt đó kiểm tra được trong SVG đã lưu ngay cả khi bản xem cắt hiển thị và cắt ngắn trông giống nhau.

![SVG thực tế mở lại so sánh bản xem tô gạch chỉ cắt hiển thị với đường gạch mở rõ ràng ở hai khoảng cách và góc 30 độ](https://perfectvector.com/blog/hatch-fill-svg-pen-paths/hatch-routes.webp)

*Mẫu kỹ thuật số tự tạo và bản xuất Paper.js thực tế. Lỗ vẫn mở trong cả ba tệp lộ trình. Các kiểm tra nói về đường tâm; không thử máy vẽ hoặc bút vật lý.*

[Hướng dẫn đơn vị họa tiết SVG](https://perfectvector.com/vi/blog/svg-pattern-units) trình bày tô lặp khi đó là đầu ra mong muốn. Ở đây đầu ra cần là hình học mở rõ ràng.

## 3. Chạy ví dụ Paper.js đầy đủ

Dùng trình duyệt, trình soạn thảo văn bản và bản dựng Paper.js 0.12.18 đầy đủ từ [bản phát hành chính thức](https://github.com/paperjs/paper.js/releases/tag/v0.12.18). Đặt `paper-full.min.js` trong thư mục `library`. Lưu HTML này thành `generate.html` và JavaScript tiếp theo thành `hatch.js` cạnh thư mục đó. Biểu trưng tự tạo được đưa vào mã.

```html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Generate original hatch routes</title>
<canvas id="work" width="200" height="140" hidden></canvas>
<p id="status">Running</p>
<pre id="export-receipt"></pre>
<h2>0 degrees, 10-unit spacing</h2>
<img id="preview-coarse" width="400" alt="Coarse hatch">
<pre id="svg-coarse"></pre>
<h2>0 degrees, 5-unit spacing</h2>
<img id="preview-dense" width="400" alt="Dense hatch">
<pre id="svg-dense"></pre>
<h2>30 degrees, 10-unit spacing</h2>
<img id="preview-angled" width="400" alt="Angled hatch">
<pre id="svg-angled"></pre>
<script src="library/paper-full.min.js"></script>
<script src="hatch.js"></script>
</html>
```

```javascript
paper.setup(document.getElementById('work'));

// Original area: a five-sided boundary with a rectangular hole.
const areaData = 'M20 20 L140 20 L180 60 L180 120 L20 120 Z ' +
  'M60 50 L60 90 L110 90 L110 50 Z';
const configurations = [
  { id: 'coarse', angle: 0, spacing: 10 },
  { id: 'dense', angle: 0, spacing: 5 },
  { id: 'angled', angle: 30, spacing: 10 }
];

function makeHatch(angle, spacing) {
  const area = new paper.CompoundPath({
    pathData: areaData,
    fillRule: 'nonzero',
    insert: false
  });
  const radians = angle * Math.PI / 180;
  const direction = new paper.Point(Math.cos(radians), Math.sin(radians));
  const normal = new paper.Point(-direction.y, direction.x);
  const center = new paper.Point(100, 70);
  const delivery = new paper.Group({ insert: false });

  for (let offset = -200 + spacing / 2; offset < 200; offset += spacing) {
    const origin = center.add(normal.multiply(offset));
    const line = new paper.Path.Line({
      from: origin.subtract(direction.multiply(300)),
      to: origin.add(direction.multiply(300)),
      insert: false
    });
    const kept = line.intersect(area, { trace: false, insert: false });
    const parts = kept instanceof paper.CompoundPath ? [...kept.children] : [kept];
    const routes = parts.filter(path => path.length > 1e-7);
    for (const path of routes) {
      if (path.closed || path.segments.length !== 2) {
        throw new Error('Expected one open straight segment');
      }
      if (path.firstSegment.point.dot(direction) > path.lastSegment.point.dot(direction)) {
        path.reverse();
      }
    }
    routes.sort((a, b) => a.firstSegment.point.dot(direction) - b.firstSegment.point.dot(direction));
    for (const path of routes) {
      path.fillColor = null;
      path.strokeColor = '#2f6977';
      path.strokeWidth = 1;
      path.strokeCap = 'butt';
      delivery.addChild(path);
    }
    if (kept instanceof paper.CompoundPath || routes.length === 0) {
      kept.remove();
    }
    line.remove();
  }
  area.remove();
  const geometry = delivery.exportSVG({ asString: true, precision: 6 });
  const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="100mm" height="70mm" ' +
    'viewBox="0 0 200 140">' + geometry + '</svg>';
  const routeCount = delivery.children.length;
  const drawnLength = delivery.children.reduce((sum, path) => sum + path.length, 0);
  let transitionLength = 0;
  for (let index = 1; index < routeCount; index += 1) {
    transitionLength += delivery.children[index - 1].lastSegment.point
      .getDistance(delivery.children[index].firstSegment.point);
  }
  delivery.remove();
  return { svg, routeCount, drawnLength, transitionLength };
}

const receipt = { paper: paper.version, units: 'viewBox user units; 0.5 mm per unit', rows: [] };
for (const configuration of configurations) {
  const result = makeHatch(configuration.angle, configuration.spacing);
  document.getElementById('svg-' + configuration.id).textContent = result.svg;
  const preview = document.getElementById('preview-' + configuration.id);
  preview.src = URL.createObjectURL(new Blob([result.svg], { type: 'image/svg+xml' }));
  receipt.rows.push({ ...configuration, route_count: result.routeCount,
    drawn_length: result.drawnLength, transition_length: result.transitionLength });
}
document.getElementById('export-receipt').textContent = JSON.stringify(receipt, null, 2);
document.getElementById('status').textContent = 'Generated. Save each exact SVG shown below, then reopen those saved files for independent checks.';
```

Mở `generate.html` trong trình duyệt. Chúng tôi chạy bằng Paper.js 0.12.18 trong Chromium 155. Mỗi kết quả hiển thị cả bản xem trước và mã SVG chính xác. Sao chép ba chuỗi SVG đầy đủ vào `hatch-coarse.svg`, `hatch-dense.svg` và `hatch-angled.svg`, rồi mở độc lập các tệp đã lưu đó.

Lệnh gọi quan trọng là `line.intersect(area, { trace: false, insert: false })`. Paper.js mô tả [`trace: false`](https://paperjs.org/reference/pathitem/#intersect-path) là chia đường đầu tại giao điểm và giữ các đường cong của nó bên trong vùng của đường thứ hai. Điều này giữ các đoạn gạch mở. Chế độ đồ theo vùng mặc định trả lời câu hỏi Boolean khác; [hướng dẫn hình có tô Paper.js](https://perfectvector.com/vi/blog/paperjs-svg-booleans) trình bày quy trình đó.

Hàm đặt `fillColor` thành null và cho mỗi lộ trình một nét. Nó cũng kiểm tra kết quả mở hai điểm trước khi xuất. Vùng kín vẫn là phần hỗ trợ dựng hình và không được đưa vào nhóm bàn giao.

## 4. Kiểm tra khoảng cách, góc và tỷ lệ vật lý cùng nhau

Cả ba bản xuất khai báo `width="100mm"`, `height="70mm"` và `viewBox="0 0 200 140"`. Điều này ánh xạ một đơn vị người dùng thành 0,5 mm trong SVG. Khoảng gạch 10 đơn vị vì thế là 5 mm; 5 đơn vị là 2,5 mm.

Các khoảng ví dụ chủ ý rộng giúp dễ kiểm tra từng lộ trình. Chúng không phải khuyến nghị cho độ phủ mực đặc. Nét màn hình rộng một đơn vị người dùng, nhưng hình thức đó không đo dấu bút thật trên vật liệu.

Vòng lặp độ lệch cố định pha gạch ở nửa khoảng cách. Đổi pha có thể đổi đặc điểm ranh giới mà đường gặp. Ở góc dương 30°, hướng chạy xuống phải trong hệ tọa độ SVG này. Khoảng cách được đo vuông góc các đường song song, không phải khoảng dọc trên màn hình.

| Tệp đã lưu         | Góc | Khoảng cách       | Lộ trình mở | Chiều dài đường tâm được vẽ          |
| ------------------ | --- | ----------------- | ----------- | ------------------------------------ |
| `hatch-coarse.svg` | 0°  | 10 đơn vị / 5 mm  | 14          | 1.320 đơn vị / 660 mm                |
| `hatch-dense.svg`  | 0°  | 5 đơn vị / 2,5 mm | 28          | 2.640 đơn vị / 1.320 mm              |
| `hatch-angled.svg` | 30° | 10 đơn vị / 5 mm  | 20          | Khoảng 1.318,564 đơn vị / 659,282 mm |

Chúng tôi tính độc lập giao điểm đường/đa giác dự kiến, rồi so sánh tọa độ đã lưu với dung sai 0,000002 đơn vị người dùng. Mọi lộ trình xuất đều khớp điểm đầu cuối dự kiến. Mỗi lộ trình đều mở và không điểm mẫu đường tâm nào vượt vào lỗ hoặc ra ngoài quá dung sai đó. Cả ba SVG đã lưu giữ ánh xạ kích thước vật lý khai báo.

Với hình khác, kiểm tra lộ trình thực xuất ra thay vì cho rằng số lượng của mẫu này vẫn áp dụng. Đường cong, khe rất nhỏ, tự giao, nhóm đã biến đổi và tài liệu SVG nhập tùy ý nằm ngoài phạm vi thử của ví dụ.

## 5. Tách khoảng giữa lộ trình khỏi kế hoạch di chuyển tối ưu

Tệp thưa có 14 lộ trình mở và 13 khoảng giữa các lộ trình liên tiếp theo thứ tự lưu. Nối các khoảng đó khi bút hạ sẽ thêm dấu ngoài ý muốn. Quy trình vẽ phải xử lý chuyển tiếp đúng ý định trước khi vẽ.

Mã giữ thứ tự một chiều đơn giản: duyệt độ lệch gạch theo thứ tự và đi mỗi đoạn cùng hướng. Cộng khoảng thẳng từ cuối mỗi lộ trình đến đầu tiếp theo cho khoảng 1.562,997 đơn vị người dùng ở tệp thưa. Tệp dày có 27 khoảng với tổng đường nối khoảng 3.281,578 đơn vị.

Những tổng đó không gồm tiếp cận đầu và quay về cuối. Đây là hệ quả hình học của thứ tự này, không phải quãng máy đo được, ước tính thời gian hoặc kế hoạch tối ưu. Ứng dụng vẽ có thể đảo hoặc sắp lại lộ trình. Giảm nửa khoảng cách làm gấp đôi chiều dài vẽ và số lộ trình của mẫu này; không xác lập quy luật gấp đôi thời gian công việc.

Mở lại tệp trong ứng dụng điều khiển máy vẽ, xác minh kích thước và kiểm tra bản xem lộ trình cùng hành vi nhấc bút. Thử bút, vật liệu, khoảng cách, khoảng lùi mép và cài đặt chuyển động trên thiết lập của bạn. Chúng tôi không chạy công việc máy vẽ, tạo mã máy hoặc thử Cricut Draw/Attach.

## Khắc phục lỗi hình học thường gặp

| Triệu chứng                             | Cần kiểm tra và thay đổi                                                                                                          |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Gạch chạy qua lỗ dự kiến                | Kiểm tra vùng có tô. Thay lớp trắng phủ bằng khoảng trống thực trong hình học phức hợp trước phép giao.                           |
| Bản xem đúng nhưng đường đầy đủ vẫn còn | Tìm phụ thuộc vào phép cắt hiển thị hoặc họa tiết. Kiểm tra tọa độ lộ trình đã lưu thay vì dựa vào hình bóng kết xuất.            |
| Đường biến thành hình kín               | Xác nhận toán hạng đầu là đường mở và có `trace: false`. Ví dụ từ chối kết quả kín hoặc nhiều đoạn.                               |
| Mực vượt ranh giới                      | Phân biệt đường tâm với vệt nét. Ví dụ không thu vùng vào theo bán kính ngòi; chuẩn bị khoảng lùi phù hợp và thử công cụ thực.    |
| Màu tô thưa hoặc bề mặt quá ướt         | Điều chỉnh qua mẫu bút/vật liệu có kiểm soát. Chỉ khoảng kỹ thuật số không xác định độ phủ hoặc cách khô.                         |
| Tệp nhảy ngoài dự kiến                  | Kiểm tra thứ tự và chuyển tiếp nhấc bút trong phần mềm đích. Giữ lộ trình gốc trước khi tối ưu, rồi kiểm tra lại lỗ và ranh giới. |

Nếu nguồn chỉ là hình bóng raster phẳng, [quy trình clipart sang SVG](https://perfectvector.com/vi/clipart-to-svg) của PerfectVector có thể giúp khôi phục hình kín trước. Kiểm tra đường bao và từng khoảng trống rồi tạo đường gạch từ hình học được chấp nhận. Vector sạch hiện có có thể đi thẳng vào chuẩn bị tô gạch.

Vector hóa hình bóng và tạo lộ trình gạch là các bước riêng. Biểu trưng tự tạo của bài này được viết bằng hình học vector; không phải mẫu chuyển đổi PerfectVector.

## Câu hỏi thường gặp

**Màu tô SVG có tự động thành đường gạch của bút không?**
Không. Màu tô mô tả hình thức được tô. Quy trình máy vẽ cần lộ trình gạch hoặc cách được hỗ trợ khác để tạo nét vẽ từ vùng đó.

**Tại sao bản xem gạch vẫn có đường xuyên lỗ?**
Phép cắt hiển thị có thể giấu phần đường đầy đủ mà không cắt ngắn hình học lưu. Kiểm tra tọa độ đã lưu và làm lỗ thành phần của vùng thực trước khi tạo lộ trình rõ ràng.

**Nên dùng khoảng gạch bao nhiêu?**
Chọn qua thử bút và vật liệu ở tỷ lệ dự kiến. Ví dụ kỹ thuật số dùng 5 mm và 2,5 mm để dễ thấy lộ trình; không xác định độ phủ đặc hay cài đặt bút chung.

**Đây có phải một đường dẫn liên tục không?**
Không. Kết quả thưa chứa 14 lộ trình mở riêng. Lỗ chia bốn hàng và quy trình vẽ phải xử lý khoảng giữa lộ trình mà không thêm dấu ngoài ý muốn.

## Nguồn

1. [Phép giao PathItem Paper.js](https://paperjs.org/reference/pathitem/#intersect-path) — Mô tả hành vi chia đường mở của trace false.
2. [Họa tiết SVG](https://www.w3.org/TR/SVG2/pservers.html#Patterns) — Định nghĩa tô lặp riêng với hình học lộ trình rõ ràng.
3. [Mặt nạ và đường cắt hiển thị CSS](https://www.w3.org/TR/css-masking-1/#ClippingPaths) — Giải thích vì sao cắt hiển thị đổi kết xuất mà không cắt hình gốc.
4. [Tô gạch GRBL-Plotter](https://grbl-plotter.de/index.php?id=hatch-fill) — Cho thấy khác biệt giữa đối tượng chồng và lỗ trong một đường dẫn.
5. [Bản phát hành Paper.js 0.12.18](https://github.com/paperjs/paper.js/releases/tag/v0.12.18) — Xác định phiên bản thư viện của ví dụ chạy được.

Nếu hình bóng chỉ có raster cần ranh giới chỉnh được, [chuẩn bị SVG clipart ứng viên](https://perfectvector.com/vi/clipart-to-svg), kiểm tra lỗ rồi tạo và xác minh riêng lộ trình gạch trước khi thử công việc vật lý.

## Explore

- [Read the HTML article](https://perfectvector.com/vi/blog/hatch-fill-svg-pen-paths)
- [Đường tạo nếp và đường cắt SVG: Đọc hình học](https://perfectvector.com/vi/blog/svg-score-lines-vs-cut-lines.md)
- [Khuôn khắc kính: Chọn phần cần bóc bỏ](https://perfectvector.com/vi/blog/glass-etching-stencil-polarity.md)
- [Product facts](https://perfectvector.com/product-facts.md)
- [FAQ](https://perfectvector.com/faq.md)
- [Pricing and credits](https://perfectvector.com/pricing.md)
