Solved

Antialiased line

Posted on 2004-04-22
20
706 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
ID: 10892212

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

Author Comment

by:ennixo
ID: 10892408
ok mokule... but how ?
0
 
LVL 30

Expert Comment

by:Axter
ID: 10893920
Are you using MFC?
0
 
LVL 30

Expert Comment

by:Axter
ID: 10893936
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
ID: 10893949
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
ID: 10893995
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
ID: 10894014
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
ID: 10894181
ok but what about the antialias ?
0
 
LVL 5

Author Comment

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

Expert Comment

by:Axter
ID: 10894213
What is antialias???

Please give more specifics for your requirement.  The more info you can give us, the better we can help you.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 30

Expert Comment

by:Axter
ID: 10894229
>>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
ID: 10894484
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
ID: 10894586
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
ID: 10895179
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
ID: 10895181
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
ID: 10895189
Sorry. I've send twice the same by dblclick
0
 
LVL 22

Expert Comment

by:grg99
ID: 10895565
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
ID: 10896844
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
ID: 10897145
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
ID: 10897162
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

929 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

12 Experts available now in Live!

Get 1:1 Help Now