找到X轴的交点,如下

时间:2017-06-27 07:21:16

标签: javascript math canvas html5-canvas symbolic-math

输入是滑块范围值Ex。( - 5到5)或(X到Y)

我希望X轴交点像这样(-5,0)( - 2,0)( - 0.5,0)(0.5,0)(2,0)(5,0)并考虑点命名从左到右从P1到P6。因此,当滑块值在中间时,P1和P2的差值(x2-x1)也是P5和P6应该相同,即0。同样,差值应该是D1> 0。 D2> D3 ....... D4< D5< D6

D1 = (P2x - P1x) D2 = (P3x - P2x) ........ ........ D5 = (P4x - P5x) D6 = (P5x - P6x)

区别应该是这样的

D1 == D6 D2 == D5 .... ....

如果滑块位于中间位置(Ex),如果范围为(-5到5),则滑块值为0

让我们解释一下-Ve方面:

如果滑块位于负侧,这意味着-5将是差异 D1> D2> D3> ...... D5> D6

如果滑块位于负侧,这意味着-4将是差异 D1> D2> D3> ...... D5> D6

依旧......

-5和-4的输出之间的差异是 -5的D1,D2,D3 ....大于D1,D2,D3 ...... -4这样将复制结果直到滑块值达到中间点,这意味着0

让我们解释+ Ve侧:

如果滑块位于正侧,这意味着差异为+5 D1< D2< D3< ...... D5< D6

如果滑块位于正侧,这意味着差异为+4 D1< D2< D3< ...... D5< D6

+5和+4的输出之间的差异是 +5的D1,D2,D3 ....大于+ 4的D1,D2,D3 ....这样会将结果复制到滑块值到达中间点,这意味着0

注意:滑块值为范围

之间的任意数字

请参考以下X轴交点的图像作为滑块值范围

img

[Spektre编辑]

好的原始问题描述与实际问题无关。问题陈述如下:找出货架分隔线的(逆向工程)位置以匹配此page的密度滑块。 (单击渐变并使用密度滚动条)。滚动条是对称的,因此从0-50%开始,其余部分可以镜像。我设法获得这些参数:

int xi[6][5]=
    {
    {0,82,145,237,344},     // 0%
    {0,100,162,245,348},    // 10%
    {0,124,180,254,353},    // 20%
    {0,140,198,264,357},    // 30%
    {0,153,224,280,365},    // 40%
    {0,161,245,294,370}     // 50%
    };
int Ti[6][4]=
    {
    {  82, 63, 92, 107 },   // 0%
    { 100, 62, 83, 103 },   // 10%
    { 124, 56, 74,  99 },   // 20%
    { 140, 58, 66,  93 },   // 30%
    { 153, 71, 56,  85 },   // 40%
    { 161, 84, 49,  76 }    // 50%
    };

其中xi[scrollbar]是近似货架分隔符位置的列表,Ti[scrollbar]是滑块状态{ 0,10,20,30,40,50 } [%]获得的货架尺寸(期间),如果您想要更精确的位置,请从此屏幕截图中获取自定义:

shelfs vs. scrollbar

棕色像V线是货架分隔线,最后一个是由于设置货架宽度而不变,所以忽略它。这里有额外的宽度以增加精度:

extra width

所以问题是如何为任何滚动条位置和预设货架总宽度计算xi

2 个答案:

答案 0 :(得分:0)

我能想到的最简单的模型会产生这样的结果,就像这样的非线性函数的正弦函数:

enter image description here

X, Y是您的绘图坐标,S是您的滑块位置,a, b, c, d, e是您需要调整以使绘图与所需结果匹配的参数。

注意:d相当不重要,因为它只是一个小的相移。 c确定滑块值更改的敏感度,b确定频率/波长变化的速度。 a只是一个垂直比例因子(幅度)。 e确定频率变化的平滑程度 - 我发现~0.15非常好。

编辑:

好的,既然你只想要X轴点,我们需要求解这个方程来找到根。以下是解决方案:

enter image description here

其中n是一个整数,它给出了你想要的每个X点。因此我们需要解决:

enter image description here

考虑到这两种情况,只需迭代所有X点的n

编辑2: 正如Blindmann指出的那样,如果e > 1,这个表达式将会出现分歧,因此约束为0 < e < 1;这将确保在{em> limit 中X接近cS它不会分歧。

答案 1 :(得分:0)

我认为您正在进行频率更改f0 -> f1 -> f0,其中滚动条Vf1所在的位置。

f(-Ve) = f0 if V!=-Ve
f( V ) = f1
f(+Ve) = f0 if V!=+Ve

将时间间隔划分为f0 -> f1f1 -> f0。首先尝试线性插值:

f(x) = f0 + (f1-f0)*(x+Ve)/(V+Ve)    x = <-Ve, V >
f(x) = f1 + (f0-f1)*(x-V )/(Ve-V)    x = < V ,+Ve>

现在只需在这里生成你的wave简单 C ++ / VCL 我为此付出了代价:

    // clear buffer
    bmp->Canvas->Brush->Color=clBlack;
    bmp->Canvas->FillRect(TRect(0,0,xs,ys));

    float y0=ys/2,A=ys/3; // zero is in middle of image and amplitudes is 1/3 image height
    float f0= 5.0*(2.0*M_PI/float(xs)); // 5 periods per image width
    float f1=25.0*(2.0*M_PI/float(xs)); // 25 periods per image width
    float V=ScrollBar1->Position; // scroll bar is from -Ve to +Ve
    const float Ve=1000;
    float f,t,x,xx,yy;

    t=0; yy=y0+A*sin(t);
    bmp->Canvas->Pen->Color=clWhite;
    bmp->Canvas->MoveTo(0,yy);
    if (V>-Ve) for (x=-Ve;x<=V;x++)
        {
        xx=(x+Ve)*xs/(2.0*Ve);          // convert x to screen position
        yy=y0+A*sin(t);                 // compute actual amplitude
        bmp->Canvas->LineTo(xx,yy);     // render it
        f=f0+(f1-f0)*(x+Ve)/(V+Ve);     // compute actual frequency
        t+=f;                           // update actual time with it
        }
    if (V<+Ve) for (x=V;x<+Ve;x++)
        {
        xx=(x+Ve)*xs/(2.0*Ve);          // convert x to screen position
        yy=y0+A*sin(t);                 // compute actual amplitude
        bmp->Canvas->LineTo(xx,yy);     // render it
        f=f1+(f0-f1)*(x-V )/(Ve-V);     // compute actual frequency
        t+=f;                           // update actual time with it
        }

    // render backbuffer
    Main->Canvas->Draw(0,0,bmp);

忽略渲染内容(将其替换为您的环境编码风格)xs,ys是图像bmp分辨率和M_PI=3.1415此处预览:

img

此处捕捉到动画 GIF (稍微降低f0,f1):

animation

有关详细信息,请参阅类似的质量检查

[Edit1],以防您确实需要交叉点

然后通过检测y轴上的符号变化来检测过零点,并从2个后续点插入位置。程序稍有变化:

// clear buffer
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));

float y0=ys/2,A=ys/3;
float f0= 1.5*(2.0*M_PI/float(xs)); // 1.5 periods per image width
float f1=10.0*(2.0*M_PI/float(xs)); // 10 periods per image width
float V=ScrollBar1->Position;
const float Ve=1000;
float f,t,x,xx,xx0,yy,yy0,r=4;

bmp->Canvas->Pen->Color=clWhite;
bmp->Canvas->Brush->Color=clWhite;
x=-Ve; t=0;
xx=(x+Ve)*xs/(2.0*Ve);          // convert x to screen position
yy=y0+A*sin(t);                 // compute actual amplitude
bmp->Canvas->MoveTo(xx,yy);     // render it
if (V>-Ve) for (x=-Ve;x<=V;x++)
    {
    xx0=xx; yy0=yy;                 // remember last point
    xx=(x+Ve)*xs/(2.0*Ve);          // convert x to screen position
    yy=y0+A*sin(t);                 // compute actual amplitude
    bmp->Canvas->LineTo(xx,yy);     // render it
    f=f0+(f1-f0)*(x+Ve)/(V+Ve);     // compute actual frequency
    t+=f;                           // update actual time with it
    if ((yy0-y0)*(yy-y0)<0.0)       // zero crossing?
        {
        if (yy!=yy0) xx0=xx0+(xx-xx0)*(yy-y0)/(yy-yy0); // interpolate crossing position
        bmp->Canvas->Ellipse(xx0-r,y0-r,xx0+r,y0+r);    // render it
        }
    }
if (V<+Ve) for (x=V;x<+Ve;x++)
    {
    xx0=xx; yy0=yy;                 // remember last point
    xx=(x+Ve)*xs/(2.0*Ve);          // convert x to screen position
    yy=y0+A*sin(t);                 // compute actual amplitude
    bmp->Canvas->LineTo(xx,yy);     // render it
    f=f1+(f0-f1)*(x-V )/(Ve-V);     // compute actual frequency
    t+=f;                           // update actual time with it
    if ((yy0-y0)*(yy-y0)<0.0)       // zero crossing?
        {
        if (yy!=yy0) xx0=xx0+(xx-xx0)*(yy-y0)/(yy-yy0); // interpolate crossing position
        bmp->Canvas->Ellipse(xx0-r,y0-r,xx0+r,y0+r);    // render it
        }
    }

// render backbuffer
Main->Canvas->Draw(0,0,bmp);

crossings

[Edit2]立方体适合交叉点

如前所述,我使用屏幕截图并为0%,10%,20%,30%,40%,50%密度滚动条位置创建一个交叉点表,并使用超宽设置。

extra wide

以像素为单位,它会以像素为单位生成此交点表:

int xi[6][9]=
    {
    { 0, 48, 102, 160, 223, 289, 358, 429, 502 },  //  0%
    { 0, 77, 124, 177, 235, 299, 364, 434, 506 },  // 10%
    { 0, 98, 150, 197, 250, 309, 372, 439, 510 },  // 20%
    { 0, 107, 175, 222, 268, 319, 379, 444, 513 }, // 30%
    { 0, 114, 190, 247, 289, 334, 389, 450, 517 }, // 40%
    { 0, 120, 200, 263, 313, 354, 400, 457, 521 }  // 50%
    };

然后我使用我的approximation search最小化平均误差来应用三次多项式拟合:

const int N=6,M=9;
double aj[M][4];
void fit_data() // fit polynomials
    {
    int i,j;
    double a0,t,dt;
    approx a1,a2,a3; double ee,e;
    dt=1.0/double(N-1);
    // fit points
    for (j=0;j<M;j++)
        {
        a0=xi[0][j];    // first coefficient is start point
        //            a0, a1,  da,n, ee
        for (a1.init(-500.0,+500.0,10.0,3,&ee); !a1.done; a1.step())
         for (a2.init(-500.0,+500.0,10.0,3,&ee); !a2.done; a2.step())
          for (a3.init(-500.0,+500.0,10.0,3,&ee); !a3.done; a3.step())
           for (ee=0.0,t=0.0,i=0;i<N;i++,t+=dt)
            ee+=fabs(double(xi[i][j])-(a0+(a1.a*t)+(a2.a*t*t)+(a3.a*t*t*t)));
        aj[j][0]=a0;
        aj[j][1]=a1.aa;
        aj[j][2]=a2.aa;
        aj[j][3]=a3.aa;
        }
    j=0;
    }

所以拟合的交点计算如下:

double compute_point(int ix,double t)
    {
    double a[9][4]=
        {
        { 0, 1.9, -9.10000000000001, 6.2 },
        { 48, 181.5, -184.1, 74.1999999999999 },
        { 102, 93.4999999999999, 105.5, -101.8 },
        { 160, 49.8, 139.9, -87.8000000000001 },
        { 223, 54.9, 26.9, 6.2 },
        { 289, 57.8, -41.2, 48.2 },
        { 358, 28.7, 3.8, 8.2 },
        { 429, 29, -18.1, 16.2 },
        { 502, 21.7, -13.1, 9.2 }
        };
    if ((ix<0)||(ix>=9)) return 0.0;
    return (a[ix][0]+(a[ix][1]*t)+(a[ix][2]*t*t)+(a[ix][3]*t*t*t));
    }

其中t=<0.0,1.0>表示滚动条设置<0%,50%>ix=<0,8>是您要获取的交叉点索引。 a[j][4]aj[j][4]表示xi[][j]表格列的三次多项式系数是相同的。

现在您只需缩放输出以匹配您的视图,并将滚动条设置的镜像添加到50%以上。这里叠加测试我检查了准确性:

overlay

红点是xi的交点,青点是为实际滚动条设置计算的交点。正如你所看到的那样,它们非常接近(GIF中缺少最后一点,但也有效,我只是忘了渲染它)。 Y轴表示滚动条设置0%位于顶部,50%位于底部。