wireviz / WireViz

Easily document cables and wiring harnesses.
GNU General Public License v3.0
4.31k stars 220 forks source link

[feature] Export technical drawing to PDF, with frame, title block, BOM #32

Open formatc1702 opened 4 years ago

formatc1702 commented 4 years ago

Here's some sample code to generate a DIN 6771 title block in code...

import svgwrite

white = svgwrite.rgb(255,255,255)
black = svgwrite.rgb(0,0,0)

thick = 0.35
thin = 0.18

# line height
f = 4.25
# width/height
w = 180
h = 9 * f
# vertical splits
v1 = 54
v2 = 98
v3 = w - 3 * f
# revision table
v_rev = [0, 6, 28, 44]
v_bottom = 4
v_top = 9
v_text = ['Rev','Changelog','Date','Name']
v_id = ['r','rc','rd','rn']
# check table
v_check = [72, 88]
c_text = ['Designed','Approved','Printed']
c_id = ['cd','cn']
# text offsets
ff = 'Arial'
fs = 2.8 # font small
fm = 4.0 # font medium
fl = 5.6 # font large
tx = 0.5
ty = -1.1

dwg = svgwrite.Drawing('example.svg', size=(w, h), profile='tiny')

# main lines
dwg.add(dwg.rect((0,0),(w,h), fill=white, stroke=black, stroke_width=thick))
dwg.add(dwg.line((v1,0),(v1,h), stroke=black, stroke_width=thick))
dwg.add(dwg.line((v2,0),(v2,h), stroke=black, stroke_width=thick))
dwg.add(dwg.line((v1,5*f),(w,5*f), stroke=black, stroke_width=thick))
dwg.add(dwg.line((v1,8*f),(w,8*f), stroke=black, stroke_width=thick))

# revision table
for i in range(1,9):
    dwg.add(dwg.line((0,i*f),(v1,i*f), stroke=black, stroke_width=thin))
for i, v in enumerate(v_rev):
    dwg.add(dwg.line((v,0),(v,h), stroke=black, stroke_width=thin))
    dwg.add(svgwrite.text.Text(v_text[i], (v + tx, 9 * f + ty), font_family=ff,font_size=fs))
    for j in range(1,9):
        dwg.add(svgwrite.text.Text('{}{}'.format(v_id[i], 9-j), (v + tx, j * f + ty), font_family=ff,font_size=fs))
# check table
for i in range(1,5):
    dwg.add(dwg.line((v1,i*f),(v2,i*f), stroke=black, stroke_width=thin))
dwg.add(dwg.line((v_check[0],0),(v_check[0],4*f), stroke=black, stroke_width=thin))
dwg.add(dwg.line((v_check[1],0),(v_check[1],5*f), stroke=black, stroke_width=thin))

# check table
dwg.add(svgwrite.text.Text('Date', (v_check[0] + tx, 1 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('Name', (v_check[1] + tx, 1 * f + ty), font_family=ff,font_size=fs))
for i, v in enumerate(c_text):
    dwg.add(svgwrite.text.Text(v, (v1 + tx, (i+2) * f + ty), font_family=ff,font_size=fs))
    for j in range(0,2):
        dwg.add(svgwrite.text.Text('{}{}'.format(c_id[j],i), (v_check[j] + tx, (i+2) * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('???', (v1 + tx, 5 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('!!!', (v_check[1] + tx, 5 * f + ty), font_family=ff,font_size=fs))

# Sheet no.
dwg.add(dwg.line((v3,5*f),(v3,8*f), stroke=black, stroke_width=thick))
dwg.add(dwg.line((v3,7*f),(w,7*f), stroke=black, stroke_width=thick))

# labels
dwg.add(svgwrite.text.Text('Part Name', (v2 + tx, 1 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('', (v2 + 2 * tx, 2 * f + 0 * 5.6), font_family=ff,font_size=fl))
dwg.add(svgwrite.text.Text('Lorem ipsum', (v2 + 2 * tx, 2 * f + 1 * 5.6), font_family=ff,font_size=fl))
dwg.add(svgwrite.text.Text('', (v2 + 2 * tx, 2 * f + 2 * 5.6), font_family=ff,font_size=fl))

dwg.add(svgwrite.text.Text('Part No.', (v2 + tx, 6 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('123-456-789', ((v2+v3)/2, 7 * f), font_family=ff,font_size=fl, text_anchor='middle'))

dwg.add(svgwrite.text.Text('Sheet', (v3 + tx, 6 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('1', ((v3+w)/2, 7 * f + ty), font_family=ff,font_size=fm, text_anchor='middle'))
dwg.add(svgwrite.text.Text('N sheets', (v3 + tx, 8 * f + ty), font_family=ff,font_size=fs))

dwg.add(svgwrite.text.Text('XXX', (v1 + tx, 9 * f + ty), font_family=ff,font_size=fs))
dwg.add(svgwrite.text.Text('YYY', (v2 + tx, 9 * f + ty), font_family=ff,font_size=fs))

dwg.save()
formatc1702 commented 4 years ago

Started some work in the feature-pdf branch.

html2pdf.py reads template.html and replaces some placeholders with the data from metadata.yml and creates output.html, which includes the image harness.svg. This could subsequently be turned into a PDF using the pdfkit package, but that is still a work in progress.

The title block is based on DIN 6771, without the top row(s). Customization with different title blocks is easy, just replace template.html.

The information currently stored in metadata.yml will just become a new section in the wireviz input file, above or below connectors, cables and connections.

BOM should be rendered as a separate table and placed above (for A4 portrait) or to the left (for A3/A2 landscape) of the title block (also work in progress)

Preview:

Screen Shot 2020-06-30 at 17 41 41
formatc1702 commented 4 years ago

If anyone proficient in HTML/CSS wants to help me improve the output of the technical drawing, please check out the feature-pdf branch and contact me!

Main issues:

Here's a preview of the two demos, in A4 and A3 respectively:

Screen Shot 2020-07-02 at 20 16 10 Screen Shot 2020-07-02 at 20 16 18
aakatz3 commented 4 years ago

Ideally, this should be rendered as a PDF/E type of document, the engineering subset. I think it supports inserting blocks, and may even have title block classes but I am not sure.

slightlynybbled commented 4 years ago

I also fiddled with pandoc a bit to see how the direct HTML conversion to PDF would look and it looks good enough for most purposes. Doesn't have the nice sign-off blocks, but it is easy.

$>pandoc test.html -o test.pdf

test.pdf

I suspect that a very nice drawing is not a version 0.2.0 type of hold up. The ability to export the PDF satisfies most users' needs and is appropriate for a v0.2.0 release. I only bring this up b/c it seems like the feature appears to be a significant barrier to the next release.

Edited to add: Changed the html image to the generated test.png in order to get pandoc to properly import the image.

formatc1702 commented 4 years ago

I suspect that a very nice drawing is not a version 0.2.0 type of hold up.

it seems like the feature appears to be a significant barrier to the next release.

It is by no means a hold up, the only thing I'm waiting for is the multicolor wires.

slightlynybbled commented 4 years ago

Great. Looking forward to next release!

aakatz3 commented 4 years ago

Update on the PDF/E thing/suggestion/note: The main reason to consider PDF/E, or additional features rather than direct HTML (granted, I haven't yet looked at the code) would be to use the different layers. Ideally, the wires, tables, BOM, and title block would all be on separate layers to allow for easier engineering management, if someone were to, for example, import the PDF into autocad, to generate a pegboard manually. I will try to look through the code soon, and the pdfkit documentation, to see if there is any easy way to specify layers for the images/bits.

formatc1702 commented 4 years ago

While this is a good idea in principle, I am unsure about the immediate usefulness. See my comment in #61, proper pegboard output would be a MASSIVE undertaking that I don't see happening anytime soon.

I'd rather focus on getting something pragmatic and good looking in the short term.

stevegt commented 3 years ago

@formatc1702 This is awesome! I was about to hack together something similar and then found this issue -- I've merged your changes from https://github.com/formatc1702/WireViz/tree/feature/technical-drw into my own https://github.com/stevegt/WireViz/tree/drawing, which is otherwise current dev + #171.

That should give anyone a starting point if they want to bring this feature into 0.3 or even sooner -- I'd start by applying the diff from https://github.com/stevegt/WireViz/commit/a48b5b936ca69bc010b04018343b3b60f8bfd22e. The merge wasn't too ugly -- ignore the html deltas; the important deltas are in Harness.py, template.html, and wireviz.py. Example usage is in the new metadata section at the top of a couple of the example .yml files.

The results are working for my use case so far. About the only thing I would change is the way the template.html is handled -- there's an older note in Harness.py about finding it from yaml or cmdline, and I also think we should continue the legacy hardcoding of a default html string to handle the case of no template file at all.

stevegt commented 3 years ago

If anyone needs a simplified title block, no BOM, US letter landscape, and only one revision row, here's a stripped-down version of template.html that does all that: https://gist.github.com/stevegt/cfd67d2df424e1b5a1ea4e0619b3f90e

pherako commented 3 years ago

It would be pretty cool if you could specify git hashes to become changelog entries in the block as well as other pieces. I'm not sure git integration was on your roadmap, but here are some ideas. The nice thing about wireviz yaml is it's version able, and git is a great versioning tool.

Here's a way:

proposed syntax:

title_block:
    - type: ansi #not sure what y'all are doing here
    - git_changelog: ea7fece5 deadbeef
    - git_descriptor: 1
    - git_version: 1

git_version would be GITHASH_LC=$(git log -n 1 --abbrev=7 --format="%h") albeit i'm personally partial to the commit count since tag, since those are monotonic like svn used to be (dinosaur here).

git_descriptor more useful imho (bash)

    GITHASH=$(git log -n 1 --abbrev=7 --format="%h")
    GITDIFF=$(git diff HEAD)
    COMMIT_LAST_TAG=$(git rev-list --tags --max-count=1)
    COMMITS_SINCE_TAG=$(git rev-list ${COMMIT_LAST_TAG}.. --count)
    if [ -z "${GITDIFF}" ]; then
        printf "${COMMITS_SINCE_TAG}-${GITHASH}"
    else
        printf "${COMMITS_SINCE_TAG}-${GITHASH}-dirty"
    fi