Solved

Opinions on best way to do this...

Posted on 2004-03-30
13
192 Views
Last Modified: 2010-04-05
Hey gang,

I'm creating an application that will accompany a board game that some friends and I play.  Basically the application is to keep track of our map movements.

I have a HUGE image that has territories on it.  I want to be able to color those territories based on who owns them.  I had originally intended to do this via the web and just use HTML but it turned into a larger task and I think it requires an application of its own.  

My question is, what is the best way to individually color each territory.  Do I need to "cut" each territory into its own image, or is there a way I can overlay a color for that specific territory?  

Each map segment (territory) can be any random shape, sort of like the board game RISK.  Plus there can be hundreds of them..  A way to individually color them without having to resort to creating a colored image for each would be nice..

Thoughts?  Did I explain what I want well enough?

I use Delphi 5 btw..

Thanks guys.
0
Comment
Question by:Palamedes
  • 5
  • 4
  • 3
  • +1
13 Comments
 
LVL 17

Expert Comment

by:mokule
ID: 10717609
Use
windows.CreatePolygonRgn
0
 
LVL 17

Expert Comment

by:mokule
ID: 10717653
Here is an example of painting
procedure TForm1.MOPaintBox1Paint(Sender: TObject);
var
  dc: HDC;
  br: HBRUSH;
  Index: integer;
  hr: HRGN;
  x,y: integer;
begin
  dc := MOPaintBox1.Canvas.Handle;
  if not bEmptyRgn then
    begin
    hr := CreateRectRgn(0,0,MOPaintBox1.Width,MOPaintBox1.Height);
    CombineRgn(hr,hr,hrd,RGN_DIFF);
    SelectClipRgn(dc,hr);
    end;
  MOPaintBox1.Canvas.Draw(0,0,imFoto.Picture.Graphic);

  SelectClipRgn(dc,hrd);
  if not bEmptyRgn then
    begin
    Index := ListBox1.ItemIndex;
    if Index >= 0 then
      begin
      x := 0;
      repeat
        y := 0;
        repeat
          imKostka.Canvas.Draw(x,y,TBitmap(ListBox1.Items.Objects[Index]));
          y := y + TBitmap(ListBox1.Items.Objects[Index]).Height-1;
        until y > imKostka.Picture.Height;
        x := x + TBitmap(ListBox1.Items.Objects[Index]).Width-1;
      until x > imKostka.Picture.Width;
      end;
    MOPaintBox1.Canvas.Draw(0,0,imKostka.Picture.Bitmap);
    end;
end;
0
 
LVL 17

Expert Comment

by:mokule
ID: 10717739
And region creation

procedure TForm1.MOPaintBox1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  hr: HRGN;
begin
  Xo := X;
  Yo := Y;
  Xp := X;
  Yp := Y;
  if tbDraw.Down then
    begin
    if ssLeft in Shift then
      begin
      if bDrawLine then
        begin
        if ilPun <= MAXPUN then
          begin
          tabPun[ilPun].x := X;
          tabPun[ilPun].y := Y;
          Inc(ilPun);
          end;
        end
      else
        begin
        bDrawLine := True;
        tabPun[0].x := X;
        tabPun[0].y := Y;
        ilPun := 1;
        end;
      end;
    if ssRight in Shift then
      begin
      if ilPun > 2 then
        begin
        if bEmptyRgn then
          begin
          hrd := CreatePolygonRgn(tabPun,ilPun,ALTERNATE);
          bEmptyRgn := False;
          end
        else
          begin
          hr := CreatePolygonRgn(tabPun,ilPun,ALTERNATE);
          bEmptyUndoRgn := False;
          CombineRgn(hru,hrd,hrd,RGN_OR);
          CombineRgn(hrd,hrd,hr,RGN_OR);
          end;
        end;
      bDrawLine := False;
      ilPun := 0;
      MOPaintBox1.Invalidate;
      end;
    end;
end;
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10717792
Mokule is right, windows.CreatePolygonRgn is the way to go.

Do you plan on having one map or many?

If your maps are going to change, you might consider creating some kind of editor by which you can create your map region ploygons with.

I recommend you look at the following articles on www.delphizine.com;

Although they are not articles on painting regions, there is great information on how to create a ploygon region editor.

If you are not a member, you can create a free limited time membership.

Shane

Hot Spots: Part I
http://www.delphizine.com/features/2002/02/di200202vh_f/di200202vh_f.asp

Hot Spots: Part II
http://www.delphizine.com/features/2002/03/di200203vh_f/di200203vh_f.asp

0
 
LVL 4

Author Comment

by:Palamedes
ID: 10717852
Thanks guys.. I'll read those articles shaneholmes.

Mokule, I'm trying to use your snippets but getting all kinds of undeclared identifiers..
bEmptyRgn, hrd, imFoto, etc..

I'm guessing you pulled this from another application?
0
 
LVL 4

Author Comment

by:Palamedes
ID: 10717876
Shane,

How do I become a free limited time member to view those articles?  I don't want to have to pay if at all possible.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 11

Expert Comment

by:shaneholmes
ID: 10717975
You didn't hear this from me, but a little bird once told me that all you had to do was create a psuedo account using a free email address (i.e. yahoo, hotmail, etc) - <SMILE>

shane
0
 
LVL 17

Expert Comment

by:mokule
ID: 10718115
Sorry for some mess.
Yes of course it was cut from bigger application.
0
 
LVL 4

Author Comment

by:Palamedes
ID: 10718139
Thanks Shane  =)

One thing I don't think I made clear though in my original question..

I need to be able to color the individual sections..  They map sections have wonderful detail that I don't want to completely overwrite.. I just want to be able to give them a HUE of the color that owns them.. so some sort of opacity is needed here..  
0
 
LVL 17

Expert Comment

by:mokule
ID: 10718148
Here should be declaratons.
But now I'm not sure wether cut it from the same version.
My fault


{
type TUndo = record
  Xp,Yp: integer;
  Xk,Yk: integer;
  op:
  end;
  }
const
  MAXPUN = 100;

type
  TForm1 = class(TForm)
    ImageList1: TImageList;
    Panel1: TPanel;
    ListBox1: TListBox;
    Panel2: TPanel;
    ToolBar1: TToolBar;
    tbRect: TToolButton;
    tbEllipse: TToolButton;
    ToolButton3: TToolButton;
    StatusBar1: TStatusBar;
    Panel3: TPanel;
    MOPaintBox1: TMOPaintBox;
    Splitter1: TSplitter;
    tbNew: TToolButton;
    tbOpen: TToolButton;
    tbSave: TToolButton;
    ToolButton5: TToolButton;
    tbUndo: TToolButton;
    tbErase: TToolButton;
    ToolButton8: TToolButton;
    ToolButton1: TToolButton;
    tbDraw: TToolButton;
    tbFoto: TToolButton;
    opDlg: TOpenPictureDialog;
    imFoto: TImage;
    imKostka: TImage;

    procedure MOPaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure MOPaintBox1MouseLeave(Sender: TObject);
    procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure FormCreate(Sender: TObject);
    procedure MOPaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MOPaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MOPaintBox1Paint(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
    procedure tbNewClick(Sender: TObject);
    procedure tbEraseClick(Sender: TObject);
    procedure tbUndoClick(Sender: TObject);
    procedure tbFotoClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure tbDrawClick(Sender: TObject);
  private
    { Private declarations }
    bPocz: boolean;
    Xo,Yo: integer;
    Xp,Yp: integer;
    hrd: HRGN;
    hru: HRGN;
    bEmptyUndoRgn: boolean;
    bEmptyRgn: boolean;
    bDrawLine: boolean;
    tabPun: array[0..MAXPUN] of TPoint;
    ilPun: integer;
  public
    { Public declarations }
  end;
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10718200
Right, like I said, the links only describe how to create your own editor to load your image (map), and create a polygon region of your map, which you can use in your painting algorithm

Shane
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10718218
What I would do once you have the polygonal region of the map, is too create a algorithm which you can invert the color in that region .

Shane
0
 
LVL 2

Accepted Solution

by:
xxflip earned 125 total points
ID: 10724351
What I did was create the regions, and create a shaded area (Green, Red, Blue, Purple, Yellow, ...) of each one, depending on the player it belongs to.

here's the Unit (the bitmap for this example and a working demo can be requested from xxflip_pt@yahoo.com),


// -------------- UNIT1.PAS
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Buttons, jpeg;

type
  TForm1 = class(TForm)
    Img: TImage;
    BitBtn1: TBitBtn;
    chRed: TCheckBox;
    chGreen: TCheckBox;
    chBlue: TCheckBox;
    Label1: TLabel;
    procedure BitBtn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    MyRegion:hRGN;
    originalImg:TBitmap;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
Var
  Points : Array[0..4] of TPoint;
begin
  //Keep a copy of the original
  Img.Picture.LoadFromFile('aa.bmp');
  originalImg:=TBitMap.Create;
  originalImg.Assign(Img.Picture.Bitmap);
  //Define Region 1
  //There are functions to get a region from a mask image
  Points[0].X := 56;  Points[0].Y := 149;
  Points[1].X := 151; Points[1].Y := 149;
  Points[2].X := 151; Points[2].Y := 282;
  Points[3].X := 113; Points[3].Y := 282;
  Points[4].X := 56;  Points[4].Y := 227;
  MyRegion:=CreatePolygonRgn(Points,5,Winding);
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
Var
  K,L:Integer;
  P:TColor;
begin
  For K := 0 to originalImg.Width do begin
    For L := 0 to originalImg.Height do begin
      //If pixel inside region then do the shading
      If PtInRegion(MyRegion,K, L) then begin
        P := originalImg.Canvas.Pixels[K, L];
        If chRed.Checked then P := (P and $FFFF00); //Red
        If chGreen.Checked then P := (P and $FF00FF); //Green
        If chBlue.Checked then P := (P and $00FFFF); //Blue
        Img.Canvas.Pixels[K, L] := P;
      end;
    end;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  originalImg.Free;
end;

end.


// -------------- UNIT1.DFM
object Form1: TForm1
  Left = 217
  Top = 106
  Width = 597
  Height = 381
  Caption = 'Region Shades'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Img: TImage
    Left = 5
    Top = 5
    Width = 463
    Height = 342
  end
  object Label1: TLabel
    Left = 475
    Top = 100
    Width = 111
    Height = 51
    AutoSize = False
    Caption = 'Try combinations of colors to get diferent shades'
    WordWrap = True
  end
  object BitBtn1: TBitBtn
    Left = 475
    Top = 5
    Width = 111
    Height = 25
    Caption = 'Color Region'
    TabOrder = 0
    OnClick = BitBtn1Click
  end
  object chRed: TCheckBox
    Left = 480
    Top = 35
    Width = 97
    Height = 17
    Caption = 'chRed'
    Checked = True
    State = cbChecked
    TabOrder = 1
  end
  object chGreen: TCheckBox
    Left = 480
    Top = 55
    Width = 97
    Height = 17
    Caption = 'chGreen'
    TabOrder = 2
  end
  object chBlue: TCheckBox
    Left = 480
    Top = 75
    Width = 97
    Height = 17
    Caption = 'chBlue'
    TabOrder = 3
  end
end
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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

757 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

21 Experts available now in Live!

Get 1:1 Help Now