Solved

Antialiased line

Posted on 2004-04-22
20
695 Views
Last Modified: 2007-12-19
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
Comment
Question by:ennixo
  • 8
  • 6
  • 5
  • +1
20 Comments
 
LVL 17

Expert Comment

by:mokule
Comment Utility

It looks like You should use LineDDA, LineDDAProc functions.
0
 
LVL 5

Author Comment

by:ennixo
Comment Utility
ok mokule... but how ?
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
Are you using MFC?
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
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
 
LVL 30

Expert Comment

by:Axter
Comment Utility
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
 
LVL 5

Author Comment

by:ennixo
Comment Utility
ok but what about the antialias ?
0
 
LVL 5

Author Comment

by:ennixo
Comment Utility
note: i don't use mfc, i don't own visual c++, i use bloodsheld dev-c++
0
 
LVL 30

Expert Comment

by:Axter
Comment Utility
What is antialias???

Please give more specifics for your requirement.  The more info you can give us, the better we can help you.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 30

Expert Comment

by:Axter
Comment Utility
>>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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
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
 
LVL 5

Author Comment

by:ennixo
Comment Utility
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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
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
 
LVL 17

Accepted Solution

by:
mokule earned 500 total points
Comment Utility
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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
Sorry. I've send twice the same by dblclick
0
 
LVL 22

Expert Comment

by:grg99
Comment Utility
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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
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
 
LVL 5

Author Comment

by:ennixo
Comment Utility
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
 
LVL 17

Expert Comment

by:mokule
Comment Utility
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 Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now