Hallo,

Ik heb hier wat paneel metertjes liggen. Nu zou ik het aluminium plaatje met de schaalverdeling willen vervangen door eentje die ik zelf kan maken met mijn laser snijmachine. Alleen zoek ik nog naar SVG of DXF-bestanden zodat ik het aluminium kan graveren / uitsnijden.

Weet iemand waar ik dit zou kunnen vinden?

Alleen zoek ik nog naar SVG of DXF-bestanden

Ik neem aan dat u bedoelt dat u tekensoftware zoekt waarmee u .svg of .dxf-bestanden kunt maken?

Er is ook 'Galva': https://www.f5bu.fr/galva-about/

Daar kunnen behoorlijk complexe ontwerpen mee gemaakt worden.

Zelf gebruik ik gewoon AutoCAD voor het tekenen van frontplaatjes en meterschalen. De output daarvan is standaard .dwg of .dxf. Meterschalen teken ik gewoon handmatig in AutoCAD, ook logaritmische, maar evt. is dit ook met AutoLISP te doen, als het echt complexe schalen moeten worden.

Volgens mij is deze vraag trouwens een maand of 3-4 geleden hier ook al aan bod gekomen?

Dit zou gemakkelijk en snel te tekenen zijn in postscript, en ik ben best bereid. Maar hoe men van postscript naar svg of dxf gaat dat zou ik niet weten, misschien bestaan er wel utilities voor. En, toegegeven, postscript is wel een beetje over de uiterste houdbaarheidsdatum heen.

Ik heb zelf goede ervaring met Frontdesigner zoals Arco voorstelt. Voordeel vond ik de schaalbaarheid dus alles heel makkelijk nog aan te passen.

Lastigste deel was dat ik een schaal wou namaken en dat het een gepuzzel was om de juiste fond te vinden, dat was net niet helemaal 100% gelukt.

Ik heb dit soort werk wel in Inkscape gedaan.

Zie de bijlage voor het originele metertje. De bedoeling is dat deze naar een schaal gaat van 1A

De eerste uitdaging was de vorm zelf, nog zonder schaal. Voor het uitsnijden van het aluminium. Dat is nu wel gelukt, dus mijn eerste testje is om te kijken of dit past.

De volgende stap is het hele plaatje zwart maken. Nu ga ik dat in eerste instantie doen met een permanente marker, maar anodiseren zou mooier zijn. Al is dat voor later.

Als dat gebeurd is, zou de laser al het zwart weg kunnen branden en de schaalverdeling achterlaten. Ik had al eentje gemaakt met chatgpt, maar dat doet toch niet helemaal wat ik wil.

De tooltjes voelen allemaal wat primitief aan, maar ik kan me voorstellen dat er niet veel mensen zijn die dit voor hun hobby doen :)

Ik ga nog eens wat proberen met de voorgestelde tools, tot zover bedankt voor de info. Een andere optie die ik overweeg, is om even een scriptje te maken die een dxf maakt. De vorm die ik wil is niet zo spannend, lijkt me niet heel ingewikkeld.

Uiteraard zijn meer tips altijd welkom.

Frontdesigner is echt heel handig voor frontpanelen en schalen.

https://www.abacom-online.de/uk/assets/images/FP_Skale_UK.GIF

Het tweaken kost wel wat tijd, maar dat is nu eenmaal altijd zo als je een proprietary schaal zelf wilt maken...

Moet het per se alu zijn? Met de 3d-printer is dit een eitje, met bv. een extra laag in een andere kleur voor de schaalverdeling.

Mwa, niet perse, maar dat heb ik en ik heb er de tools voor. Daarnaast is het resultaat superieur. Met de printer krijg je nooit zulke fijne details.

Verder staat het ook een beetje los van de vraag natuurlijk, het front moet getekend worden ongeacht de productie methode. Ik dacht dit te delen, wellicht dat men het interessant vind.

Als ik wat resultaten heb, zal ik ze wel delen.

---
Klein testje gedaan. Heb chatgpt om een svg gevraagd. Nog niet helmaal wat ik wil maar tis wel bruikbaar.

Met een 0603 voor vergelijk.

[Bericht gewijzigd door hardbass op (16%)]

Ik heb dat soort dingen al opgelost door ze onder de scanner te gooien, en dan in inkscape om te zetten naar vector en te bewerken.

Dat is ongeveer het enige waar ik nog een flatbedscanner voor heb ;)

Ik heb ooit een paneelmetertje getekend in een webpagina. Dat ging met javascript om svg naar de browser te schrijven.

En op dezelfde manier kun je dat ook doen met een stukje python script.

Dat ziet er dan zo uit:

En dit is het script :


#!/bin/python3

import math

def cos(x):
   return math.cos(math.radians(x))

def sin(x):
   return math.sin(math.radians(x))

def Write(s):
   print(s)

class Object:
   pass

Width       = 300
Height      = 150

# Scale parameters
Scale = Object()
Scale.Min          =   0.0
Scale.Max          =   1.0
Scale.Div          =   0.2
Scale.NrDecimals   =   1

Scale.SubDivisions = [ 2, 5]
Scale.Angle        =  90   # Degrees
Scale.Radius       = 140   # pixels
Scale.Caption      = "A"

def SvgFont():
   return f'font-size="16" fill="black" style="font-family:Serif" '

DoPointer = False

# Draw meter x on the screen
def DrawMeter():

   Write(f'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="{Width}" height="{Height}">')

   # Define clipping area
   Write(f'<clipPath id="MyScaleBoundary">')
   Write(f'   <rect x="0" y="0" width="{Width}" height="{Height}"/>')
   Write(f'</clipPath>')

   # Set clippath because IE does not clip svg viewport by default
   Write(f'<g clip-path="url(#MyScaleBoundary)" stroke="black" stroke-width="1" fill="white">')

   # Draw panelmeter border with rouded corners
   Write(f'   <rect x="1" y="1" width="{Width - 2}" height="{Height - 2}" rx="20" ry="20"/>')

   r  = Scale.Radius       # Scale radius
   cx = Width / 2          # Circle center x
   cy = 60 + Scale.Radius  # Circle center y

   def SvgRotate(Angle):
      return f'transform="rotate({Angle} {cx} {cy})"'

   def SvgArcPos(Angle):
      x = cx + sin(Angle) * r
      y = cy - cos(Angle) * r
      return f'{x},{y}'

   Write(f'   <g fill="black" stroke="black">')

   # Scale baseline
   Write(f'      <path d="M {SvgArcPos(-Scale.Angle/2)} A {r} {r} 0 0,1 {SvgArcPos(+Scale.Angle/2)}" fill="none"/>')

   # -- Scale divisions
   Delta  = (Scale.Angle / ((Scale.Max - Scale.Min) / Scale.Div) ) # Degrees per divison
   Delta /= (Scale.SubDivisions[0] * Scale.SubDivisions[1])        # Degrees per SubSubdivision

   Count1 = 0
   Count2 = 0
   Dial = Scale.Min

   Angle = - Scale.Angle / 2
   while(True):
      if(Angle > (Scale.Angle / 2) + 0.01):
         break;

      if (Count1 == 0):
         Write(f'      <path d="M {cx},{cy-r} V {cy-r-15}" {SvgRotate(Angle)} />')
         Write(f'      <text x="{cx}" y="{cy-r-20}" text-anchor="middle" {SvgRotate(Angle)} {SvgFont()}>{Dial:.{Scale.NrDecimals}f}</text>')
         Dial += Scale.Div

      elif(Count2 == 0):
         Write(f'      <path d="M {cx},{cy-r} V {cy-r-10}" {SvgRotate(Angle)}/>')

      else:
         Write(f'      <path d="M {cx},{cy-r} V {cy-r-5}"  {SvgRotate(Angle)}/>')

      if(Count1 == 0):
         Count1 = Scale.SubDivisions[0] * Scale.SubDivisions[1]

      if(Count2 == 0):
         Count2 = Scale.SubDivisions[1]

      Count1 -= 1
      Count2 -= 1
      Angle  += Delta

   Write(f'   </g>')

   # Write Label Text in the meter
   Write(f'   <text x="{cx}" y="{cy-r+40}" text-anchor="middle" fill="black">{Scale.Caption}</text>')

   if(DoPointer):
      # Draw a Pointer with Arrow-Head
      Write(f'   <g transform="rotate(-45 {cx} {cy})">')
      Write(f'      <path d="M {cx},{cy} V {cy-r+5}"/>')
      Write(f'      <polygon points="{cx},65 {cx-5},95 {cx+5},95"/>')
      Write(f'   </g>')
      Write(f'   <circle cx="{cx}" cy="{cy}" r="60" fill="black" />')

   Write(f'</g>')
   Write(f'</svg>')

DrawMeter()

Wel leuk iedereen doet het weer net even iets anders en op de manier die hem het beste ligt en waar in het verleden ook al is mee gewerkt.

Ik denk dat de manier van deKees het beste binnen mijn skills vallen. Dit is natuurlijk anders voor iedereen. Al moet ik toegeven dat die laatste screenshot van Arco er ook wel erg makkelijk uit ziet.

Wat ik zelf hier makkelijk aan vind is:
- Ik kan al programmeren en hoef me niet te verdiepen om een nieuwe tool te leren gebruiken.
- Hoef geen licentie te kopen voor een tool die ik wellicht maar een keer gebruik.
- Dit kan ik makkelijk kopiëren en plakken naar bijvoorbeeld ChatGPT om zo dingen aan te passen.

Nu ik dit zie gaan de hersens weer goed tekeer, ik zou zo een heel frontpaneel in elkaar kunnen programmeren.

Bedankt voor de input, ik kan weer verder!

Graag gedaan.

Ik heb het zo gemaakt dat je wat kun spelen met de parameters bovenaan, om varianten te kunnen maken.

Met name dit stukje:


Width       = 300
Height      = 150

# Scale parameters
Scale = Object()
Scale.Min          =   0.0
Scale.Max          =   1.0
Scale.Div          =   0.2
Scale.NrDecimals   =   1

Scale.SubDivisions = [ 2, 5]
Scale.Angle        =  90   # Degrees
Scale.Radius       = 140   # pixels
Scale.Caption      = "A"

Ben het met Benleentje eens, leuk om anderman's oplossingen te zien. En ieder gebruikt de technieken, of software, waar hij al mee bekend is. In mijn geval AutoCAD, voor anderen misschien zelfs Photoshop. En een derde tekent het mogelijk zelfs met de hand, sjabloontjes en een Rotring-pen.... Vele wegen leiden naar Rome.

Bij deze trouwens een foto van een projectje (batterijtester) waar ik ooit een keer een 'quick & dirty' nieuwe wijzerschaal voor heb getekend. Niet m'n mooiste en beste, maar het werkt.

Het programma 'Galva', dat ik eerder vermeldde, kan ook gebruikt worden voor behoorlijk gecompliceerde zaken als bijv. rekenschijven. Zoals deze, om (o.a.) reflectiedemping (of SWR) te bepalen. Zie bijlage. (bij het zoeken naar deze zelfbouw rekenschijf stuitte ik weer op Fred101's website https://www.pa4tim.nl/zelfbouw/mbt-meten/gain-loss-swr-rl-draaischijf/. Blijkbaar ben ik niet de enige die deze calculator heeft nagebouwd :) )

Overigens, als u zich toch bezighoudt met CNC-bewerkingen neem ik aan dat u ook de beschikking hebt over CAD-software, en ermee om kunt gaan? Dan zou mij dát eigenlijk de simpelste oplossing lijken om een meterschaal te tekenen.

De laser software die ik gebruik (ezcad) heeft meer bugs dan features. Een svg importeren ging helemaal fout. Dus heb ik met behulp van AI dit omgetoverd tot een dxf.

De tweede aanpassing was om de lijnen te vervangen voor rechthoeken zodat de laser dit kan opvullen met hatching.

Na een beetje prutsen en pielen heb ik nu dit. Het is vast niet perfect, maar het doet voor mij wat het moet.


#!/bin/python3

import math
import os
import ezdxf

# Visual Parameters
CHAR_SCALE = 8.0               # Height of one character
CHAR_THICKNESS = 1              # Thickness of segments

TICK_THICKNESS = 0.4
TICK_LENGTH_MAJOR = 15
TICK_LENGTH_MEDIUM = 10
TICK_LENGTH_MINOR = 5
TEXT_OFFSET_X = 6
TEXT_OFFSET_Y = 2
TEXT_SPACING = 1.6             # Multiplier for character spacing

# Output
script_dir = os.path.dirname(os.path.abspath(__file__))
output_path = os.path.join(script_dir, "output.dxf")

Width = 50
Height = 25

# Scale settings
class Scale:
    Min = 0.0
    Max = 1.0
    Div = 0.2
    NrDecimals = 1
    SubDivisions = [2, 5]
    Angle = 90
    Radius = 140
    Caption = "A"

# Setup
doc = ezdxf.new()
msp = doc.modelspace()

r = Scale.Radius
cx = Width / 2
cy = 60  # center

def polar(angle_deg, radius):
    a = math.radians(angle_deg)
    return cx + math.sin(a) * radius, cy + math.cos(a) * radius

def draw_solid_line(msp, x1, y1, x2, y2, thickness=TICK_THICKNESS):
    dx = x2 - x1
    dy = y2 - y1
    length = math.hypot(dx, dy)
    if length == 0:
        return
    ux = dx / length
    uy = dy / length
    nx = -uy * (thickness / 2)
    ny = ux * (thickness / 2)

    p1 = (x1 + nx, y1 + ny)
    p2 = (x1 - nx, y1 - ny)
    p3 = (x2 - nx, y2 - ny)
    p4 = (x2 + nx, y2 + ny)

    msp.add_lwpolyline([p1, p2, p3, p4, p1], close=True)

def draw_segment(msp, x1, y1, x2, y2, thickness):
    dx = x2 - x1
    dy = y2 - y1
    full_length = math.hypot(dx, dy)
    if full_length == 0:
        return

    ux = dx / full_length
    uy = dy / full_length
    nx = -uy * (thickness / 2)
    ny = ux * (thickness / 2)

    tip = thickness * 0.6
    shorten = thickness

    sx1 = x1 + ux * shorten
    sy1 = y1 + uy * shorten
    sx2 = x2 - ux * shorten
    sy2 = y2 - uy * shorten

    p1 = (sx1 + nx, sy1 + ny)
    p2 = (sx1 - nx, sy1 - ny)
    p3 = (sx2 - nx, sy2 - ny)
    p4 = (sx2 + nx, sy2 + ny)

    tip1 = (sx1 - ux * tip, sy1 - uy * tip)
    tip2 = (sx2 + ux * tip, sy2 + uy * tip)

    points = [tip1, p1, p4, tip2, p3, p2, tip1]
    msp.add_lwpolyline(points, close=True)

def draw_seg_a(msp, x, y, scale, thickness): draw_segment(msp, x, y + 2*scale, x + scale, y + 2*scale, thickness)
def draw_seg_b(msp, x, y, scale, thickness): draw_segment(msp, x + scale, y + 2*scale, x + scale, y + scale, thickness)
def draw_seg_c(msp, x, y, scale, thickness): draw_segment(msp, x + scale, y + scale, x + scale, y, thickness)
def draw_seg_d(msp, x, y, scale, thickness): draw_segment(msp, x, y, x + scale, y, thickness)
def draw_seg_e(msp, x, y, scale, thickness): draw_segment(msp, x, y + scale, x, y, thickness)
def draw_seg_f(msp, x, y, scale, thickness): draw_segment(msp, x, y + 2*scale, x, y + scale, thickness)
def draw_seg_g(msp, x, y, scale, thickness): draw_segment(msp, x, y + scale, x + scale, y + scale, thickness)
def draw_seg_dp(msp, x, y, scale, thickness): msp.add_circle((x, y), thickness * scale * 0.2)

segment_lookup = {
    'A': draw_seg_a,
    'B': draw_seg_b,
    'C': draw_seg_c,
    'D': draw_seg_d,
    'E': draw_seg_e,
    'F': draw_seg_f,
    'G': draw_seg_g,
    'DP': draw_seg_dp,
}

char_segments = {
    '0': (['A', 'B', 'C', 'D', 'E', 'F'], 1.0),
    '1': (['B', 'C'], 1.0),
    '2': (['A', 'B', 'G', 'E', 'D'], 1.0),
    '3': (['A', 'B', 'G', 'C', 'D'], 1.0),
    '4': (['F', 'G', 'B', 'C'], 1.0),
    '5': (['A', 'F', 'G', 'C', 'D'], 1.0),
    '6': (['A', 'F', 'G', 'E', 'C', 'D'], 1.0),
    '7': (['A', 'B', 'C'], 1.0),
    '8': (['A', 'B', 'C', 'D', 'E', 'F', 'G'], 1.0),
    '9': (['A', 'B', 'C', 'D', 'F', 'G'], 1.0),
    '-': (['G'], 1.0),
    '.': (['DP'], 0.4),  # Much narrower width
}

def draw_char_segments(msp, ch, x, y):
    segments, _ = char_segments.get(ch, ([], 1.0))
    for seg in segments:
        func = segment_lookup[seg]
        func(msp, x, y, CHAR_SCALE, CHAR_THICKNESS)

def draw_text(msp, text, x, y):
    pos = x
    for ch in text:
        segments, width = char_segments.get(ch, ([], 1.0))
        draw_char_segments(msp, ch, pos, y)
        pos += CHAR_SCALE * TEXT_SPACING * width

def draw_meter():
    Delta = Scale.Angle / ((Scale.Max - Scale.Min) / Scale.Div)
    Delta /= (Scale.SubDivisions[0] * Scale.SubDivisions[1])

    Count1 = 0
    Count2 = 0
    Dial = Scale.Min
    Angle = -Scale.Angle / 2

    while Angle <= (Scale.Angle / 2 + 0.01):
        x1, y1 = polar(Angle, r)
        if Count1 == 0:
            x2, y2 = polar(Angle, r + TICK_LENGTH_MAJOR)
            draw_solid_line(msp, x1, y1, x2, y2)
            xt, yt = polar(Angle, r + 35)
            draw_text(msp, f"{Dial:.{Scale.NrDecimals}f}", xt - TEXT_OFFSET_X, yt + TEXT_OFFSET_Y)
            Dial += Scale.Div
        elif Count2 == 0:
            x2, y2 = polar(Angle, r + TICK_LENGTH_MEDIUM)
            draw_solid_line(msp, x1, y1, x2, y2)
        else:
            x2, y2 = polar(Angle, r + TICK_LENGTH_MINOR)
            draw_solid_line(msp, x1, y1, x2, y2)

        if Count1 == 0:
            Count1 = Scale.SubDivisions[0] * Scale.SubDivisions[1]
        if Count2 == 0:
            Count2 = Scale.SubDivisions[1]

        Count1 -= 1
        Count2 -= 1
        Angle += Delta

    draw_text(msp, Scale.Caption, cx - TEXT_OFFSET_X, cy + r + 30)

# Run
draw_meter()
doc.saveas(output_path)
print(f"DXF saved to: {output_path}")

Het programma "Galva" heeft werkelijk zeer veel mogelijkheden m.b.t. allerhande tekenwerk, niet alleen voor het ontwerpen van nieuwe schalen voor paneelmeters. Je kunt er bijv. ook frontplaten mee ontwerpen of technische tekeningen maken of millimeter papier of grafische plots met lineaire of logaritmische assen van data tekenen, dit is lang niet alles wat Galva kan.
Op de website staan heel veel voorbeelden (als pdf en script) als download (alles zit ook in de zip file van Galva zelf) om te laten zien waartoe Galva in staat is.
Het UI van het programma is niet het allermodernste of het makkelijkste in gebruik (het werkt op script basis) maar de mogelijkhden van Galva zijn geweldig.

Ik was Galva ook tegengekomen op internet. Maar eerlijk gezegd heb ik het niet echt een kans gegeven. Het schrok me best af dat veel in het Frans is, mijn Frans begint en eindigt bij bonjour.

Nu geloof ik wel dat het erg krachtig is met het script­systeem dat ze hebben. En als je de tool al kent, dan geloof ik wel dat dit sneller is dan zelf iets schrijven. Zeker als het complexer wordt dan de schaal die ik nodig heb. Maar eerlijk gezegd heb ik geen zin om weer door allemaal documentatie te spitten en uit te zoeken hoe het allemaal werkt.

De redenen om toch zelf te programmeren:

- Ik ken het al, hoef geen nieuwe 'taal' te leren
- AI kent het ook, kan heel makkelijk dingetjes genereren. (Dit heb ik niet geprobeerd met GalvaScript, wellicht kent AI dat ook, maar ik verwacht niet zo goed als met Python)
- Ik kan alle tooling gebruiken die ik ken en makkelijk vind: Git, VSCode met auto-aanvulling en Copilot
- Als er iets mist, kan ik het zelf erbij programmeren
- Een stukje python schrijven vind ik ook veel leuker om te doen dan weer allemaal documentatie doorspitten
- Mijn schaaltje is simpel, dus dat was ook makkelijk zelf te programmeren. Zeker met het voorbeeldje van deKees was het eigenlijk al klaar.

Wat ook een leuk programma is:
https://sourceforge.net/projects/glx/
GLE, Graphics Layout Engine. Het heeft helaas geen DXF output maar wel PDF.
Het geen tekenprogramma maar een scripting programma met grafische output.

Nog een paar linkjes:
https://www.tonnesoftware.com/meter2.html
https://community.element14.com/technologies/open-source-hardware/b/bl…

Ja, en dan heb je een svg o.i.d. en dan? Inkscape kan plaatjes naar g-codes omzetten om te graveren of laseren. Printen met een laserprinter kan natuurlijk ook. Papieren plak-etiketten voor zw/wit. Er is ook aluminium-achtig spul te koop waar je b.v. hele mooie typeplaatjes mee kunt maken met een laser printer. Uittekenen in Freecad is ook een mogelijkheid, maar vereist wel een leercurve heb ik ondervonden. Zeker als je het 'parametrisch' wilt maken.

Hallo,

Het is gelukt hoor, met het scriptje heb ik de schaal gemaakt. Met een andere tool de outline getekend. Zie hier het resultaat.

Ik ben er tevreden mee.