Blog Metlivi

Como criar um traço de pena de ponta larga deslizando uma forma fixa ao longo de um caminho

Para criar um traço de pena de ponta larga, defina uma ponta retangular estreita, mantenha seu ângulo constante e translade-a ao longo de um caminho. O traço é a união de todas as posições ocupadas por esse retângulo. Sua espessura varia conforme a direção do movimento, embora a ponta nunca mude de tamanho.

Este guia mostra como construir essa geometria para um desenho vetorial ou um detalhe de personagem. Você definirá a ponta, deslizará com ela continuamente ao longo de uma polilinha e gerará SVG usando um programa Python completo. A construção central evita os espaços que podem surgir quando um pincel é simulado com marcas separadas.

29 de outubro de 2026Leitura de 8 minPor Metlivi Editorial Team
Seção 1

O que significa deslizar uma forma fixa?

Separe o desenho em duas entradas: um caminho que descreve por onde o ponto de referência da ponta se desloca e uma área que descreve a região coberta pela ponta em uma posição. Coloque o ponto de referência da área na origem. Em cada posição do caminho, some essa posição a cada ponto da área.

Matematicamente, o conjunto resultante é S = {p + n | p belongs to P, n belongs to N}, em que P é o caminho e N é a ponta. Essa é uma soma de Minkowski, seguindo a definição ponto a ponto do manual do usuário de somas de Minkowski 2D do CGAL.

Nesta construção, “fixa” significa que tanto a área quanto sua orientação permanecem constantes nas coordenadas do desenho. A ponta translada sem girar para acompanhar o caminho. Manter o ponto de referência no centro do retângulo faz com que o caminho descreva o centro da ponta em movimento.

Seção 2

Como o ângulo da ponta e a direção do movimento determinam a espessura?

Escolha três parâmetros: a dimensão maior do retângulo w, sua dimensão menor h e o ângulo α da aresta maior. Um valor pequeno e positivo de h dá à ponta uma espessura mínima visível. Já uma ponta ideal em forma de segmento de reta tem espessura zero e pode deixar uma marca de área nula quando se move exatamente na mesma direção.

Para um segmento de caminho reto com ângulo de direção θ, a largura da ponta retangular medida perpendicularmente ao movimento é:

width across the stroke = w × |sin(θ − α)| + h × |cos(θ − α)|

Essa fórmula decorre da projeção das duas dimensões perpendiculares do retângulo sobre a normal ao caminho. Ela descreve um segmento reto ou a projeção local da área ao longo de uma curva suave; partes sobrepostas de um traço curvo podem tornar sua silhueta geral mais larga.

Para uma ponta ilustrativa de 24 unidades por 3 unidades, o movimento paralelo à aresta maior produz uma faixa com 3 unidades de largura. O movimento perpendicular produz uma faixa com 24 unidades de largura. Com uma diferença de 45°, a largura é aproximadamente (24 + 3) / √2, ou 19,09 unidades. São dimensões calculadas, não resultados medidos de um pincel.

Use essas três direções como teste de calibração antes de desenhar uma curva complicada. Elas mostram se o ângulo e as dimensões se comportam como esperado, sem exigir que você interprete várias curvas sobrepostas.

Seção 3

Como deslizar continuamente sem deixar espaços entre marcas?

Para uma ponta convexa que se move ao longo de um único segmento reto, faça uma cópia da ponta em cada extremidade e calcule o fecho convexo dos vértices combinados. Esse fecho corresponde exatamente à área percorrida durante a translação ao longo do segmento.

O motivo é simples: cada posição intermediária é uma interpolação linear entre as posições das extremidades. Como a ponta é convexa, o fecho contém precisamente essas posições interpoladas. Essa construção por segmento é uma consequência direta da definição de soma de Minkowski, e não um recurso separado de pincel.

Para um retângulo, cada segmento fornece apenas oito pontos candidatos: quatro cantos no início e quatro no fim. Calcule o fecho deles, repita para cada par consecutivo de pontos do caminho e combine os polígonos resultantes. Os deslizamentos adjacentes compartilham a posição completa da ponta no ponto final comum, então a geometria tem cobertura contínua.

Não calcule um único fecho convexo para o caminho inteiro. Isso preencheria as curvas e apagaria as reentrâncias pretendidas. O fecho pertence a cada segmento individual; o traço completo é a união deles.

Uma ponta côncava exige outro tratamento. Calcular seu fecho preencheria suas reentrâncias. Decomponha-a em partes convexas, deslize cada parte e combine os resultados. O CGAL documenta a abordagem relacionada de decomposição e união para somas de Minkowski de polígonos não convexos.

Seção 4

Como implementar o deslizamento em Python?

O programa completo a seguir requer Python 3 e sua biblioteca padrão. Ele define um caminho de exemplo com cinco pontos, constrói uma ponta retangular e imprime um documento SVG com quatro polígonos preenchidos do deslizamento. Salve-o como broad_edge.py e execute python broad_edge.py > stroke.svg para criar o desenho.

As coordenadas seguem a convenção SVG usada aqui: x aumenta para a direita e y aumenta para baixo. Portanto, um ângulo positivo neste programa inclina a ponta no sentido horário na tela. Interfaces de desenho podem usar outra convenção para os ângulos.

from math import cos, sin, radians


def hull(points):
    pts = sorted(set(points))
    if len(pts) <= 1:
        return pts

    def cross(o, a, b):
        return ((a[0] - o[0]) * (b[1] - o[1])
                - (a[1] - o[1]) * (b[0] - o[0]))

    def half(sequence):
        out = []
        for p in sequence:
            while len(out) >= 2 and cross(out[-2], out[-1], p) <= 0:
                out.pop()
            out.append(p)
        return out

    return half(pts)[:-1] + half(reversed(pts))[:-1]


def sweep(path, width=24, thickness=3, angle=30):
    if not path or width <= 0 or thickness <= 0:
        raise ValueError(
            'Provide a nonempty path and positive nib dimensions'
        )

    a = radians(angle)
    u = (cos(a), sin(a))
    v = (-sin(a), cos(a))
    nib = [
        (s * width * u[0] / 2 + t * thickness * v[0] / 2,
         s * width * u[1] / 2 + t * thickness * v[1] / 2)
        for s, t in [(-1, -1), (1, -1), (1, 1), (-1, 1)]
    ]
    pairs = list(zip(path, path[1:])) or [(path[0], path[0])]
    return [
        hull([(p[0] + q[0], p[1] + q[1])
              for p in (start, end) for q in nib])
        for start, end in pairs
    ]


path = [(40, 45), (85, 125), (140, 150), (195, 110), (245, 45)]
polygons = sweep(path)
all_points = [p for polygon in polygons for p in polygon]
x0, y0 = (min(p[i] for p in all_points) - 5 for i in (0, 1))
x1, y1 = (max(p[i] for p in all_points) + 5 for i in (0, 1))

svg = [
    '<svg xmlns="http://www.w3.org/2000/svg" '
    f'viewBox="{x0} {y0} {x1 - x0} {y1 - y0}">',
    '<g fill="#23364d" stroke="none">'
]
for polygon in polygons:
    coordinates = ' '.join(f'{x:.6f},{y:.6f}' for x, y in polygon)
    svg.append(f'<polygon points="{coordinates}"/>')
svg.extend(['</g>', '</svg>'])
print('\n'.join(svg))

O programa trata um único ponto no caminho desenhando uma área da ponta. Pontos consecutivos repetidos também produzem uma área, sem exigir o cálculo de uma direção. Caminhos vazios e dimensões não positivas da ponta geram um erro. Forneça pares de coordenadas numéricas finitas; este exemplo compacto não valida dados de caminho importados.

A construção foi executada com as coordenadas de exemplo: ela produziu quatro polígonos de deslizamento com seis vértices, e o SVG gerado foi analisado corretamente como XML. Os casos de ponto único e ponto repetido também foram verificados. Essas verificações confirmam a construção e a estrutura do documento; não constituem um teste de renderização visual.

Seção 5

Como lidar com curvas, cantos e extremidades?

O exemplo é exato para sua polilinha, sujeito à aritmética de ponto flutuante e ao arredondamento de coordenadas. Para usar uma curva de Bézier, primeiro aproxime-a com segmentos retos e, em seguida, aplique o mesmo deslizamento. Adicione mais segmentos onde a curva se dobra acentuadamente, em vez de distribuir todas as amostras uniformemente pelo parâmetro da curva.

Escolha a tolerância de aproximação de acordo com o tamanho de saída pretendido. Por exemplo, um desvio de um quarto de pixel pode ser uma meta inicial para exibição, seguida de uma inspeção na maior escala planejada. Essa é uma escolha ilustrativa de engenharia, não um limite universal de qualidade. Vale lembrar que subdividir um segmento já reto não altera sua área percorrida.

Mantenha separados os caminhos de traços distintos. Passar pontos de dois traços desconectados em uma única chamada criaria um deslizamento de conexão indesejado. Gere cada traço separadamente e reúna seus polígonos na saída.

Na extremidade, a ponta mantém toda a sua área. Em um canto, os dois deslizamentos vizinhos se sobrepõem. Este modelo não acrescenta nenhuma junção em ponta ou extremidade arredondada. As propriedades comuns de traço do SVG definem suas próprias construções de extremidades e junções, então adicioná-las introduziria geometria além deste deslizamento com ponta fixa. Consulte as definições de extremidades e junções de traço do SVG 2.

Seção 6

Quando é necessário unir os polígonos?

O programa exporta polígonos preenchidos sobrepostos. Para uma visualização em cor sólida, eles representam a cobertura percorrida sem exigir uma biblioteca de união de polígonos. No entanto, permanecem como objetos editáveis separados; o programa não calcula um único contorno consolidado.

Se você precisa de uma silhueta limpa para editar o contorno posteriormente, calcule a união booleana de todos os polígonos dos segmentos. Preserve os eventuais furos no resultado. Um caminho em laço pode circundar uma região sem pintura, e preencher todos os contornos fechados alteraria o traço.

A transparência também exige cuidado. Aplicar fill-opacity parcial separadamente aos polígonos sobrepostos pode escurecer as regiões de sobreposição. Para obter translucidez uniforme, aplique a opacidade ao grupo que os contém ou una a geometria antes de aplicar a opacidade do preenchimento. O SVG distingue a opacidade do preenchimento de um objeto da opacidade do grupo em sua especificação de pintura.

Resultado pretendido Próxima etapa adequada
Visualização em cor sólida Mantenha os polígonos preenchidos do deslizamento
Visualização translúcida uniforme Aplique a opacidade ao grupo que os contém
Uma silhueta editável Una os polígonos do deslizamento com uma operação booleana
Ponta personalizada côncava Decomponha a ponta antes de deslizar
Traço curvo suave Aproxime a curva e depois deslize seus segmentos
Seção 7

Como diagnosticar um traço inesperado?

Comece pelas direções de calibração e, em seguida, inspecione o caminho e a construção da saída. Altere uma entrada de cada vez para que a origem de uma diferença visível permaneça clara.

  • A espessura permanece quase constante: Verifique se a ponta está girando junto com o caminho. O ângulo dela deve permanecer fixo nas coordenadas do desenho.
  • Surgem espaços visíveis entre as marcas: Substitua as marcas isoladas pela construção do fecho convexo de cada segmento.
  • Uma cunha larga preenche a parte interna de uma curva: Verifique se você calculou por engano um fecho para vários segmentos do caminho em conjunto.
  • As extremidades parecem arredondadas: Verifique se há um traço comum adicional ou se a área da ponta é diferente.
  • Uma curva original suave parece angular: Refine a aproximação por polilinha em torno das curvas.
  • Aparecem conexões inesperadas: Mantenha os caminhos desconectados em chamadas separadas de deslizamento.

Se estiver comparando o resultado com a ferramenta Caligrafia do Inkscape, a documentação oferece verificações úteis dos parâmetros: Fixação em 100 mantém o ângulo fixo, Afinamento em 0 remove a variação de largura baseada na velocidade, e os controles de pressão e inclinação podem alterar a largura e o ângulo. Desative essas entradas variáveis ao examinar o comportamento de uma ponta fixa. Essas configurações descrevem os controles da ferramenta; elas não demonstram que sua saída seja idêntica a esta construção retangular. Consulte a documentação da barra de ferramentas Caligrafia do Inkscape.

Um traço de ponta larga confiável começa com um caminho de calibração simples e uma área claramente definida. Quando os testes paralelo, perpendicular e diagonal se comportarem corretamente, use o mesmo deslizamento por segmento no caminho escolhido, refine as partes curvas de acordo com a escala de saída e una os polígonos quando a próxima etapa de edição exigir uma única silhueta.

Seção 8

Fontes

Leituras relacionadas

Continue explorando o tema