Para um aplicativo de desenho, estou salvando as coordenadas de movimento do mouse em uma matriz e desenhando-as com lineTo. A linha resultante não é suave. Como posso produzir uma única curva entre todos os pontos reunidos?
Eu pesquisei no Google, mas encontrei apenas 3 funções para desenhar linhas: para 2 pontos de amostra, basta usar lineTo
. Para 3 pontos de amostra quadraticCurveTo
, para 4 pontos de amostra bezierCurveTo
,.
(Tentei desenhar um bezierCurveTo
para cada 4 pontos na matriz, mas isso leva a dobras a cada 4 pontos de amostra, em vez de uma curva suave contínua.)
Como escrevo uma função para desenhar uma curva suave com 5 pontos de amostra e além?
Respostas:
O problema de unir os pontos de amostra subsequentes às funções disjuntas do tipo "curveTo" é que o local onde as curvas se encontram não é suave. Isso ocorre porque as duas curvas compartilham um ponto final, mas são influenciadas por pontos de controle totalmente disjuntos. Uma solução é "curvar-se" para os pontos médios entre os próximos 2 pontos de amostra subsequentes. Unir as curvas usando esses novos pontos interpolados fornece uma transição suave nos pontos finais (o que é um ponto final para uma iteração se torna um ponto de controle para a próxima iteração.) Em outras palavras, as duas curvas desconexas têm muito mais em comum agora.
Esta solução foi extraída do livro "Foundation ActionScript 3.0 Animation: Making Things Move". p.95 - técnicas de renderização: criando múltiplas curvas.
Nota: esta solução, na verdade, não passa por cada um dos pontos, que era o título da minha pergunta (ela aproxima a curva pelos pontos de amostra, mas nunca passa pelos pontos de amostra), mas, para meus propósitos (um aplicativo de desenho), é bom o suficiente para mim e, visualmente, você não percebe a diferença. Não é uma solução para passar por todos os pontos de amostragem, mas é muito mais complicado (ver http://www.cartogrammar.com/blog/actionscript-curves-update/ )
Aqui está o código do desenho para o método de aproximação:
fonte
Um pouco tarde, mas para constar.
Você pode obter linhas suaves usando splines cardinais (também conhecidas como splines canônicas) para desenhar curvas suaves que atravessam os pontos.
Eu criei essa função para tela - ela é dividida em três funções para aumentar a versatilidade. A função principal do wrapper é assim:
Para desenhar uma curva tem uma matriz com x, y pontos na ordem:
x1,y1, x2,y2, ...xn,yn
.Use-o assim:
A função acima chama duas subfunções, uma para calcular os pontos suavizados. Isso retorna uma matriz com novos pontos - esta é a função principal que calcula os pontos suavizados:
E para desenhar os pontos como uma curva suavizada (ou qualquer outra linha segmentada, desde que você tenha uma matriz x, y):
Mostrar snippet de código
Isso resulta nisso:
Você pode estender a tela facilmente para poder chamá-la assim:
Adicione o seguinte ao javascript:
Você pode encontrar uma versão mais otimizada disso no NPM (
npm i cardinal-spline-js
) ou no GitLab .fonte
ptsa
deve serpts
, ou então lançaria erros.A primeira resposta não passará por todos os pontos. Este gráfico passará exatamente por todos os pontos e será uma curva perfeita com os pontos como [{x:, y:}] em tais pontos.
fonte
Como Daniel Howard aponta , Rob Spencer descreve o que você deseja em http://scaledinnovation.com/analytics/splines/aboutSplines.html .
Aqui está uma demonstração interativa: http://jsbin.com/ApitIxo/2/
Aqui está como um trecho caso o jsbin esteja inoperante.
fonte
Eu achei que isso funcionava bem
fonte
Decido adicionar, em vez de postar minha solução em outro post. Abaixo está a solução que eu construo, pode não ser perfeita, mas até agora a saída é boa.
Importante: passará por todos os pontos!
Se você tem alguma idéia, para melhorar , compartilhe comigo. Obrigado.
Aqui está a comparação do antes depois:
Salve este código em HTML para testá-lo.
fonte
Experimente o KineticJS - você pode definir um Spline com uma matriz de pontos. Aqui está um exemplo:
URL antigo: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
Consulte o URL do arquivo: https://web.archive.org/web/20141204030628/http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
fonte
Incrivelmente atrasado, mas inspirado pela resposta brilhantemente simples de Homan, permita-me postar uma solução mais geral (geral no sentido de que a solução de Homan trava em conjuntos de pontos com menos de 3 vértices):
fonte
Para adicionar ao método de splines cardinais do K3N e talvez abordar as preocupações de TJ Crowder sobre curvas 'mergulhando' em lugares enganosos, inseri o seguinte código na
getCurvePoints()
função, pouco antesres.push(x);
Isso efetivamente cria uma caixa delimitadora (invisível) entre cada par de pontos sucessivos e garante que a curva permaneça dentro dessa caixa delimitadora - ie. se um ponto na curva estiver acima / abaixo / esquerda / direita dos dois pontos, ele altera sua posição para estar dentro da caixa. Aqui o ponto médio é usado, mas isso poderia ser melhorado, talvez usando interpolação linear.
fonte
Se você deseja determinar a equação da curva através de n pontos, o código a seguir fornecerá os coeficientes do polinômio de grau n-1 e salvará esses coeficientes na
coefficients[]
matriz (começando no termo constante). As coordenadas x não precisam estar em ordem. Este é um exemplo de um polinômio de Lagrange .fonte