Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 747
  • Last Modified:

Antialiased line

Hi, i need a function to draw a line from (x1,y1) to (x2,y2) on a device context. i need to be able to set a thickness and to draw the line AND/OR to get a Mask which contains the modified pixels (black=not modified, white=modified).
0
ennixo
Asked:
ennixo
  • 8
  • 6
  • 5
  • +1
1 Solution
 
mokuleCommented:

It looks like You should use LineDDA, LineDDAProc functions.
0
 
ennixoAuthor Commented:
ok mokule... but how ?
0
 
AxterCommented:
Are you using MFC?
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
AxterCommented:
If you're using mfc, then you can use member function CDC::LineTo.

A full and complete answer is hard to give with out know more details of your requirement.
0
 
AxterCommented:
If you're using WIN32 code with NO mfc, then you can still use the API function LineTo.
BOOL LineTo(
  HDC hdc,    // device context handle
  int nXEnd,  // x-coordinate of ending point
  int nYEnd   // y-coordinate of ending point
);
0
 
mokuleCommented:
In the meantime i've change my mind about LineDDA

{
HBITMAP hb;
HDC dc, mdc;
HPEN hp;
int width;

dc = PaintBox1->Canvas->Handle;
width = 10;

// You'll have Your mask here
mdc = CreateCompatibleDC(dc);
hb = CreateCompatibleBitmap(dc,200,200);
SelectObject(mdc,hb);
hp = CreatePen(PS_SOLID,width,0xffffff);
SelectObject(mdc,hp);
MoveToEx(mdc,10,10,NULL);
LineTo(mdc,150,20);

BitBlt(dc,0,0,200,200,mdc,0,0,SRCCOPY);

DeleteObject(hp);
DeleteObject(hb);
DeleteDC(mdc);
}
0
 
AxterCommented:
I forgot to mention, for WIN32 LineTo call, you need to first call MoveToEx to set starting position, and then call LineTo.

For MFC, you need to call CDC::MoveTo before calling CDC::LineTo.
0
 
ennixoAuthor Commented:
ok but what about the antialias ?
0
 
ennixoAuthor Commented:
note: i don't use mfc, i don't own visual c++, i use bloodsheld dev-c++
0
 
AxterCommented:
What is antialias???

Please give more specifics for your requirement.  The more info you can give us, the better we can help you.
0
 
AxterCommented:
>>note: i don't use mfc, i don't own visual c++, i use bloodsheld dev-c++
This is the kind of information you want to give when posting your question.

You probably would have received an answer sooner, if your question had more details.
0
 
mokuleCommented:
This is very slow drawing antialias lines. Developped under BCB 6
Can You use this functions in Your compiler?

//---------------------------------------------------------------------------
// header file (*.h)

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:      // IDE-managed Components
        TPaintBox *PaintBox1;
        TButton *Button1;
        TPaintBox *PaintBox2;
        void __fastcall Button1Click(TObject *Sender);
private:      // User declarations
public:            // User declarations
        __fastcall TForm1(TComponent* Owner);
   void __fastcall DrawLine(HDC dc, int width, int mul);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// source file (*.cpp)

void __fastcall TForm1::Button1Click(TObject *Sender)
{
// first canvas area 200x200 - multiplier 1 - no antialias
DrawLine(PaintBox1->Canvas->Handle,10,1);
// first canvas area 200x200 - multiplier 5 -antialias
DrawLine(PaintBox2->Canvas->Handle,10,5);
}

void __fastcall TForm1::DrawLine(HDC dc, int width, int mul)
{
HBITMAP hb,hb2;
HDC mdc,mdc2;
HPEN hp;
int r,g,b;
COLORREF cl;
int x,y,i,j;

mdc2 = CreateCompatibleDC(dc);
hb2 = CreateCompatibleBitmap(dc,200*mul,200*mul);
SelectObject(mdc2,hb2);

mdc = CreateCompatibleDC(dc);
hb = CreateCompatibleBitmap(dc,200,200);
SelectObject(mdc,hb);

hp = CreatePen(PS_SOLID,mul*width,0x0000ff);
SelectObject(mdc2,hp);

MoveToEx(mdc2,10*mul,50*mul,NULL);
LineTo(mdc2,190*mul,60*mul);

DeleteObject(hp);

hp = CreatePen(PS_SOLID,mul*width,0x00ffff);
SelectObject(mdc2,hp);

MoveToEx(mdc2,60*mul,10*mul,NULL);
LineTo(mdc2,70*mul,120*mul);

for(x = 0 ; x < 200 ; x++)
  for(y = 0 ; y < 200 ; y++)
    {
    r = 0;
    g = 0;
    b = 0;
    for(i = 0 ; i < mul ; i++)
      for(j = 0 ; j < mul ; j++)
        {
        cl = GetPixel(mdc2,mul*x+i,mul*y+j);
        r += GetRValue(cl);
        g += GetGValue(cl);
        b += GetBValue(cl);
        }
    r /= mul*mul;
    g /= mul*mul;
    b /= mul*mul;
    SetPixel(mdc,x,y,RGB(r,g,b));
    }

BitBlt(dc,0,0,200,200,mdc,0,0,SRCCOPY);

DeleteObject(hp);
DeleteObject(hb);
DeleteDC(mdc);

DeleteDC(mdc2);
DeleteObject(hb2);
}
0
 
ennixoAuthor Commented:
what i would like is something like it draws the line pixel after pixel in a loop so that only getpixel and setpixel are used...
0
 
mokuleCommented:
Better not try to tell me there is something wrong this time :)

should be improved (by You)
1. currently must be x2 >= x1, y2 >= y1
2. not good ends of line
3. width is doubled (giving 3 line will have about 6 pixels width)


//---------------------------------------------------------------------------
void __fastcall DrawLine(HDC dc,int x1,int y1,
                                int x2,int y2,
                                int width,int cl)
{
int i,j,x,y;
double A,B,C,N;
double dl;
int r1,g1,b1;
int cl1;
int r2,g2,b2;

// line equation Ax+By+C=0
if(x1 == x2)
  {
  A = 1;
  B = 0;
  C = -x1;
  }
else
  {
  A = (double)(y2-y1)/(x1-x2);
  B = 1;
  C = -y1-A*x1;
  }
N = sqrt(A*A+B*B);

// pen color
r2 = GetRValue(cl);
g2 = GetGValue(cl);
b2 = GetBValue(cl);

for(i = x1- width ; i < x2+ width ; i++)
  {
  for(j = y1- width ; j < y2+ width ; j++)
    {
    dl = fabs((A*i+B*j+C)/N);   // point distance from line
    if(dl <  width-1 )
      SetPixel(dc,i,j,cl);  // draw with pen color
    else if( dl <  width+1)
      {
// background color
      cl1 = GetPixel(dc,i,j);
      r1 = GetRValue(cl1);
      g1 = GetGValue(cl1);
      b1 = GetBValue(cl1);
// draw with color depending from distance
      SetPixel(dc,i,j,RGB(r2+(r1-r2)*(dl- width+1)/2,
                          g2+(g1-g2)*(dl- width+1)/2,
                          b2+(b1-b2)*(dl- width+1)/2));
      }
    }
  }
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
DrawLine(PaintBox1->Canvas->Handle, 10,10,180,20,2,clRed);
DrawLine(PaintBox1->Canvas->Handle, 80,10,83,160,1,clGreen);
DrawLine(PaintBox1->Canvas->Handle, 120,10,136,170,0,clBlue);
}

0
 
mokuleCommented:
Better not try to tell me there is something wrong this time :)

should be improved (by You)
1. currently must be x2 >= x1, y2 >= y1
2. not good ends of line
3. width is doubled (giving 3 line will have about 6 pixels width)


//---------------------------------------------------------------------------
void __fastcall DrawLine(HDC dc,int x1,int y1,
                                int x2,int y2,
                                int width,int cl)
{
int i,j,x,y;
double A,B,C,N;
double dl;
int r1,g1,b1;
int cl1;
int r2,g2,b2;

// line equation Ax+By+C=0
if(x1 == x2)
  {
  A = 1;
  B = 0;
  C = -x1;
  }
else
  {
  A = (double)(y2-y1)/(x1-x2);
  B = 1;
  C = -y1-A*x1;
  }
N = sqrt(A*A+B*B);

// pen color
r2 = GetRValue(cl);
g2 = GetGValue(cl);
b2 = GetBValue(cl);

for(i = x1- width ; i < x2+ width ; i++)
  {
  for(j = y1- width ; j < y2+ width ; j++)
    {
    dl = fabs((A*i+B*j+C)/N);   // point distance from line
    if(dl <  width-1 )
      SetPixel(dc,i,j,cl);  // draw with pen color
    else if( dl <  width+1)
      {
// background color
      cl1 = GetPixel(dc,i,j);
      r1 = GetRValue(cl1);
      g1 = GetGValue(cl1);
      b1 = GetBValue(cl1);
// draw with color depending from distance
      SetPixel(dc,i,j,RGB(r2+(r1-r2)*(dl- width+1)/2,
                          g2+(g1-g2)*(dl- width+1)/2,
                          b2+(b1-b2)*(dl- width+1)/2));
      }
    }
  }
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
DrawLine(PaintBox1->Canvas->Handle, 10,10,180,20,2,clRed);
DrawLine(PaintBox1->Canvas->Handle, 80,10,83,160,1,clGreen);
DrawLine(PaintBox1->Canvas->Handle, 120,10,136,170,0,clBlue);
}

0
 
mokuleCommented:
Sorry. I've send twice the same by dblclick
0
 
grg99Commented:
The slow and obvious way is to draw the line or image several times larger than desired, then average each 2x2 or 3x3 or whatever group of pixels.   yawningly obvious, straightforward, and boring.   Not to mention very very very very very very very very slooow.  

There are much faster ways to anti-alias lines than with all that arithmetic.   See Micheal Abrash's book "The Zen of Graphics programming".   In there he shows how to QUICKYLY draw anti-aliased lines.  The technique is to use Breshenham's algorithm, but instead of just setting black or white pixels, each pixel along the line is set in proportion to how close it is to the optimum line.  It's easily calculated using fixed-point math.   Amazing but true.

0
 
mokuleCommented:
grg99:
In my first pieceof code I've used the first method You mention

void __fastcall TForm1::DrawLine(HDC dc, int width, int mul)
parameter mul is specifying this factor

In my second piece of code I've used the second method. Never read this book. Just invented it myself :)) on the pressure of ennixo.
I haven't used fixed arithmetic though.
0
 
ennixoAuthor Commented:
mokule:
great ! some things need to be changed but i had no idea on how to draw an antialiased line and now i know !
perhaps you d'be able to answer this question too : http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_20963350.html
0
 
mokuleCommented:
for example this should be changed

for(i = x1- width ; i < x2+ width ; i++)
  {
  for(j = y1- width ; j < y2+ width ; j++)

to

for(i = x1- width-1 ; i < x2+ width+1 ; i++)
  {
  for(j = y1- width-1 ; j < y2+ width+1 ; j++)
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 8
  • 6
  • 5
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now