Well I am trying to build a few small windows applications using MFC and trying to learn how things work, and while drawing a country's flag I got stuck. Following lines of code draw three rectangles and a circle right at the center of middle rectangle, what need to do next is draw spokes in to circle, i.e 8 diameters separated by an angle of 45 degrees.
void CMainWindow::OnPaint (){
CPaintDC dc(this);
for (int i=0;i <=100;i+=50) {
dc.SetBkMode(TRANSPARENT);
CRect rect;
CPen pen(PS_SOLID, 1, RGB(0,0,0));
CPen *oldPen = dc.SelectObject(&pen);
if (i == 0){
CBrush brush(RGB(255,130,0));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(75,(i+50),275,(i+100));
}
else if(i == 50) {
CBrush brush(RGB(255,255,255));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(75,(i+50),275,(i+100));
CPen pen2(PS_SOLID, 1,RGB(0,0,255));
CPen *oldPen = dc.SelectObject(&pen2);
dc.Ellipse(150,100,200,150);
}
else {
CBrush brush(RGB(34,139,34));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(75,(i+50),275,(i+100));
}
}
I have no clue how to do that, I tried to find it in the MFC library but no luck!
Here is an example of the sin() cos() method.
I didn't see the point of putting the whole code block in a for loop, show I removed that part.
#include "math.h"
#define PI 3.1415926535898
void DrawIndiaFlag(CDC & dc , int x, int y)
{
dc.SetBkMode(TRANSPARENT);
CRect rect;
CPen pen(PS_SOLID, 1, RGB(0,0,0));
CPen *oldPen = dc.SelectObject(&pen);
{
CBrush brush(RGB(255,130,0));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(x,(y),x+200,(y+50));
dc.SelectObject(oldBrush);
}
{
CBrush brush(RGB(255,255,255));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(x,(50+y),x+200,(y+100));
CPen pen2(PS_SOLID, 1,RGB(0,0,255));
CPen *oldPen = dc.SelectObject(&pen2);
dc.Ellipse(x+75,y+50,x+125,y+100);
// Draw spokes
int nOriginX = x+100;
int nOriginY = y+75;
int nRadius = 25;
int nSpokes = 24;
double fAngle = 2*PI/nSpokes;
for (int i =0; i<nSpokes; i++)
{
dc.MoveTo(nOriginX,nOriginY);
int nX = (int)ceil(cos((fAngle)*i)*(nRadius)+nOriginX);
int nY = (int)ceil(sin((fAngle)*i)*(nRadius)+nOriginY);
dc.LineTo(nX,nY);
}
dc.SelectObject(oldPen);
}
{
CBrush brush(RGB(34,139,34));
CBrush *oldBrush = dc.SelectObject(&brush);
dc.Rectangle(x,(100+y),x+200,(150+y));
dc.SelectObject(oldBrush);
}
dc.SelectObject(oldPen);
}
I'm not familiar with the API your are using, but you could;
start with a thin rectangle (assuming there is no line function) as your line
draw it from the centre of the circle to the top, this should be an easy co-ordinate to work out
take those starting positions from your first line and rotate them around the centre of the circle, if their is no API function for this you could do it manually as described here http://www.euclideanspace.com/maths/geometry/affine/aroundPoint/index.htm
Use these new rotated co-ordinates to draw your next line, then just repeat
I think what you're after is the CDC::LineTo method (you can use CDC::MoveTo to get to the start point). More info:
"Draws a line from the current position up to, but not including, the point specified by x and y (or point)... The line is drawn with the selected pen. The current position is set to x, y or to point."
Related
So I made the Sierpinski carpet fractal in processing using a Square data type which draw a square and has a function generate() that generates 9 equal squares out of itself and returns an ArrayList of (9-1)=8 squares removing the middle one (it is not added to the returned ArrayList) in order to generate the Sierpinski carpet.
Here is the class Square -
class Square {
PVector pos;
float r;
Square(float x, float y, float r) {
pos = new PVector(x, y);
this.r = r;
}
void display() {
noStroke();
fill(120,80,220);
rect(pos.x, pos.y, r, r);
}
ArrayList<Square> generate() {
ArrayList<Square> rects = new ArrayList<Square>();
float newR = r/3;
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
if (!(i==1 && j==1)) {
Square sq = new Square(pos.x+i*newR, pos.y+j*newR, newR);
rects.add(sq);
}
}
}
return rects;
}
}
This is the main sketch which moves forward the generation on mouse click -
ArrayList<Square> current;
void setup() {
size(600, 600);
current = new ArrayList<Square>();
current.add(new Square(0, 0, width));
}
void draw() {
background(255);
for (Square sq : current) {
sq.display();
}
}
void mousePressed() {
ArrayList<Square> next = new ArrayList<Square>();
for(Square sq: current) {
ArrayList<Square> rects = sq.generate();
next.addAll(rects);
}
current = next;
}
The problem :
The output that I am getting has very thin white lines which are not supposed to be there :
First generation -
Second generation -
Third generation -
My guess is that these lines are just the white background that shows up due to the calculations in generate() being off by a pixel or two. However I am not sure about how to get rid of these. Any help would be appreciated!
Here's a smaller example that demonstrates your problem:
size(1000, 100);
noStroke();
background(0);
float squareWidth = 9.9;
for(float squareX = 0; squareX < width; squareX += squareWidth){
rect(squareX, 0, squareWidth, height);
}
Notice that the black background is showing through the squares. Please try to post this kind of minimal example instead of your whole sketch in the future.
Anyway, there are three ways to fix this:
Option 1: Call the noSmooth() function.
By default, Processing uses anti-aliasing to make your drawings look smoother. Usually this is a good thing, but it can also add some fuzziness to the edges of shapes. If you disable anti-aliasing, your shapes will be more clear and you won't see the artifacts.
Option 2: Use a stroke with the same color as the fill.
As you've already discovered, this draws an outline around the shape.
Option 3: Use int values instead of float values.
You're storing your coordinates and sizes in float values, which can contain decimal places. The problem is, the screen (the actual pixels on your monitor) don't have decimal places (there is no such thing as half a pixel), so they're represented by int values. So when you convert a float value to an int, the decimal part is dropped, which can cause small gaps in your shapes.
If you just switch to using int values, the problem goes away:
size(1000, 100);
noStroke();
background(0);
int squareWidth = 10;
for(int squareX = 0; squareX < width; squareX += squareWidth){
rect(squareX, 0, squareWidth, height);
}
I'm trying to draw bears in processing, (Just simple circles), how can I get the bears equally spaced apart, and have the same space from the edge of the screen to the bears, on either side? As well as vertically.
I know this is vague, but I'm terrible at explaining things
Because you does not provide any code or example I will just tell you how to place circle in the middle of sketch.
For simplicity imagine this set up:
void setup(){
size(400, 400);
}
1) Very basic approach would be to hard code position of this circle into ellipse draw function.
ellipse(200, 200, 50, 50);
Where first two parameters are coordinates for circle center. Simple find out from size 400x400 that mid is on coord 200x200. This is bad approach and you should avoid using it.
2) Better approach would be to calculate center coord using global variables width and height
ellipse(width/2, height/2, 50, 50);
3) When you are drawing or moving more complex objects it is preferred to use some function to draw this objects always with same fixed position in our example
void draw_circle(){
ellipse(0, 0, 50, 50);
}
And just moving center of drawing using transformations so our draw function will looks like this
void draw(){
pushMatrix();
translate(width/2, height/2);
draw_circle();
popMatrix();
}
Using this you could be able to draw bears equally spaced apart and from sides.
It sounds like you want a grid of equally spaced circles. For that you just need to divide your space into a grid in the x and y directions. The simplest way to do this is to wrap the kind of thing Majlik showed inside a double loop to move from cell to cell in your 'virtual' grid. To see this more clearly, in the code below there is an extra little bit so that if you press the 'g' key (for grid) you'll see the grid cells, with a circle centered in each one. You can press any other key to make the grid go away.
You can see that each way gives the same result: inside draw() uncomment the one you want and comment out the other 2.
int nx = 4; // number of circles horizontally
int ny = 5; // number of circles vertically
int divx;
int divy;
int diameter = 40;
void setup() {
size(600, 600);
// calculate width and hegith of each cell of the grid
divx = width/nx;
divy = height/ny;
}
// 3 ways to draw a regular grid of circles
void draw() {
background(200);
// show the cell layout if the g key was typed, otherwise don't
if(key == 'g')
drawGrid();
// 1 way
for(int i = 0; i < nx; i++) {
for(int j = 0; j < ny; j++ ) {
ellipse(i * divx + divx/2, j * divy + divy/2, diameter, diameter);
}
}
// another way
// for(int i = divx/2; i < width; i += divx) {
// for(int j = divy/2; j < height; j += divy ) {
// ellipse(i, j, diameter, diameter);
// }
// }
// yet another way
// for(int i = divx/2; i < width; i += divx) {
// for(int j = divy/2; j < height; j += divy ) {
// pushMatrix();
// translate(i, j);
// ellipse(0, 0, diameter, diameter);
// popMatrix();
// }
// }
}
void drawGrid() {
// draw vertical lines
for(int i = 1; i < nx; i++) {
line(i * divx, 0, i * divx, height);
}
// draw horizontal lines
for(int j = 1; j < ny; j++ ) {
line(0, j * divy, width, j * divy);
}
}
I am new to Processing.js and need a little bit support with this issue. I have made a HTML-Canvas animation where I have lines with a curtain like behavior which can be seen here:
Click
this is made with a canvas plugin called Paper.js
I now want to get similar effect on processing but don't really know how to figure it out. My attempt was:
float x;
float y;
void setup() {
size(1024, 768);
strokeWeight(2);
background(0, 0, 0);
}
void mouseMoved() {
x = mouseX;
y = mouseY;
}
void draw() {
background(0);
line(50, 50, x += x - x/5, y += y - y/5);
stroke(255, 255, 255);
line(50, 700, x += x - x/15, y += y - y/15);
stroke(255, 255, 255);
line(75, 50, x += x - x/25, y += y - y/25);
stroke(255, 255, 255);
line(75, 700, x += x - x/35, y += y - y/35);
// and so on, would create it within a loop
}
So what I am trying to do is basically get the same effect which I have done in HTML and adapt it in Processing.js.
Thanks in advance.
I'd strongly recommend ignoring the paper.js and reimplementing this properly. We're seeing a sequence of lines that connect to a historical line of coordinates, based on mouse position, so let's just implement that:
class Point {
float x, y;
Point(float _x, float _y) { x=_x; y=_y; }}
// our list of historical points
ArrayList<Point> points;
// the horizontal spacing of our lines has fixed interval
float interval;
// how many lines do we want to draw?
int steps = 50;
void setup() {
size(500, 500);
// initialise the "history" as just the midpoint
points = new ArrayList<Point>();
for (int i=0; i<steps; i++) {
points.add(new Point(width/2, height/2));
}
// compute the horizontal interval, because it's
// width-dependent. Never hard code dependent values.
interval = width/(float)steps;
// the lower we set this, the slower it animates.
frameRate(60);
}
void draw() {
// white background, black lines
background(255);
stroke(0);
// for each historic point, draw two
// lines. One from height 0 to the point,
// another from height [max] to the point.
Point p;
for (int i=0; i<steps; i++) {
p = points.get(i);
line(interval/2 + i*interval, 0, p.x, p.y);
line(interval/2 + i*interval, height, p.x, p.y);
}
// when we move the mouse, that counts as a new historic point
points.remove(0);
points.add(new Point(mouseX, mouseY));
}
Sketch running in the browser: http://jsfiddle.net/M2LRy/1/
(You could speed this up by using a round-robin array instead of an ArrayList, but ArrayLists are pretty convenient here)
The code below draws a spiral using objects from a string array. Everything is fine, except that I would like the text objects to be drawn at a roughly 45 degree angle at each instance (based on the current x, y coordinates in the code below) rather than being drawn horizontally (when the text is horizontally drawn, it naturally overlaps with other text at concentrated points along the top & bottom of the curve). I researched some methods, but I'm still very new to all of this, and potential solutions have all evaded me.
String example = "";
String[] wordSet = split(example, " ");
float x, y;
float angle = 0;
float radiusSpiralLine = 10;
size (800, 800);
translate(width/2, height/2);
background(#ffffff);
smooth();
fill(0);
for (int i = 0; i < wordSet.length; i++) {
angle += .05;
radiusSpiralLine += .5;
x = cos(angle) * radiusSpiralLine;
y = sin(angle) * radiusSpiralLine;
textSize(9);
text(wordSet[i], x, y);
}
Here is tutorial to very similar problem. In basic you need to store projection matrix by pushMatrix() then translate and rotate according to position of letter on curve and then restore matrix by popMatrix(). I don't know how exactly do you want to rotate you text but just fold round your text() function like this maybe it will help you:
pushMatrix();
translate(x, y);
rotate(angle);
text(wordSet[i], 0, 0);
popMatrix();
First, you should start getting in the habit of wrapping code in the setup() and draw() functions. Since you're drawing a static image you don't need the draw() function, but I think it's good practice to have those two.
Now, what you are doing now is simply translating the words by a very small amount. Do the math:
x = cos(angle) * radiusSpiralLine; //cos(.05)*.5 = .499
y = sin(angle) * radiusSpiralLine; //sin(.05)*.5 = .024
That means they move less than a pixel, and they're not rotating at all.
What you need is your good ol' friend, the rotate() function.
Let's re-write code:
String example = "These are a bunch of words going around!";
String[] wordSet = split(example, " ");
float x, y;
float angle = 0;
void setup() {
size (800, 800);
background(#ffffff);
smooth();
fill(0);
pushMatrix();
translate(width/2, height/2); //Translate when you need to translate, not before
for (int i = 0; i < wordSet.length; i++) {
angle = PI/5; //Our good friends, radians
textSize(20); //What is this, text for ants? Change to 20
rotate(angle);
text(wordSet[i], 20, 0);
}
popMatrix();
}
void draw() {
}
First notice, the setup() and draw(). I like them there. It looks nicer, I think.
A couple of important things to note.
The effects of rotate() and translate() are on the canvas are cumulative.
We could have had the same effect in different ways:
for (int i = 0; i < wordSet.length; i++) {
angle = PI/5;
textSize(20);
rotate(angle); //always rotating by PI/5 ON TOP of previous rotation
text(wordSet[i], 20, 0);
}
//Everything from now on will still be rotated, we don't want that!
Slightly better, but not there yet:
for (int i = 0; i < wordSet.length; i++) {
angle += PI/5; //constantly increasing the angle
textSize(20);
pushMatrix(); //push a new canvas on top of everything
rotate(angle); //rotate by angle (which increases every loop)
text(wordSet[i], 20, 0);
popMatrix(); //pop the rotated canvas out, go back to original canvas
} //Things won't be rotated, but they'll still be translated, since translate() is outside of pushMatrix and popMatrix
Hope this helps.
I need to make an interactive graph using MFC
It will be sort of like an equalizer control, where the user should be able to click on a point on the equalizer drag it to change it's y axis value
I am also just starting to learn MFC
Upto this point I have used CPaintDC in the OnPaint() function to draw the graph in a dialog box. For now the graph is very simple, with rectangle boarder, filled with white colour, and 4 points on the graph. I use OnMouseMove() function to know if the cursor is inside the graph area and OnLButtonDown() function to know where the user has clicked. If the user has clicked at a position which implies I want to change the y axis value of the graph point at that location, I repaint the figure using Invalidate() and calling OnPaint() inside OnLButtonDown(). However, every time the graph has to update, I can see a flicker. it is not a problem now, but I will need to extend this graph so that it has at least 64 changeable points, with the ability to change the y axis value for a point by dragging instead of just clicking where I want it to go. Will the flickering problem increase as I increase the number of points and the complexity of the appearance of the graph? The graph will need to have axes, gridlines, labels, etc later on. Is the flickering something I should be concerned about? Is there any way I can prevent it?
----UPDATE ----
This is how I updated my OnPaint() function according to how I understood CodeDreamer's suggestion
void Cgraph_on_dlgboxDlg::OnPaint()
{
CPaintDC dc_blt(this);
CDC dc;
CBitmap bmpDC;
CRect rcClient;
GetClientRect(rcClient);
if (IsIconic())
{
// CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
dc.CreateCompatibleDC(&dc);
bmpDC.CreateCompatibleBitmap(&dc, theGraph.width,theGraph.height );
dc.SelectObject(&bmpDC);
CPen pen;
COLORREF pencolour = RGB(0, 0, 0);
COLORREF brushcolour = RGB(0, 0, 255);
COLORREF graphColour = RGB(0, 0, 150);
// Draw boarder
pen.CreatePen(PS_SOLID, 3, pencolour);
// CBrush brush(HS_CROSS, brushcolour);
dc.SetBkMode(TRANSPARENT);
dc.SetMapMode(MM_TEXT);
dc.SetViewportOrg(theGraph.x1, theGraph.y1);
dc.SelectObject(&pen);
// Draw graph boundary
CPoint point1(0,0);
point1.x = 0;
point1.y = 0;
CPoint point2(0,0);
point2.x = point1.x + theGraph.width;
point2.y = point1.y + theGraph.height;
dc.Rectangle(CRect(point1, point2));
pen.DeleteObject();
// Draw Horizontal at 0
pen.CreatePen(PS_SOLID, 1, pencolour);
dc.SelectObject(&pen);
dc.MoveTo(0, theGraph.height - ORG_DIST_FROM_BOTTOM);
dc.LineTo(theGraph.width, theGraph.height - ORG_DIST_FROM_BOTTOM);
pen.DeleteObject();
dc.SetViewportOrg(theGraph.x1, theGraph.y1 + theGraph.height - ORG_DIST_FROM_BOTTOM); // dc.SetViewportOrg() always works relative to the clinet origin
// Draw graph line
pen.CreatePen(PS_SOLID, 2, graphColour);
dc.SelectObject(&pen);
for(int i = 0; i<NUM_OF_SECTIONS_IN_GRAPH; i++){
dc.MoveTo(graphSamplePoints[i].x, graphSamplePoints[i].y);
dc.LineTo(graphSamplePoints[i+1].x, graphSamplePoints[i+1].y);
}
// draw circles at graph sample points
for(int i = 0; i<NUM_OF_POINTS_IN_GRAPH; i++){
CIRCLE(dc, graphSamplePoints[i].x, graphSamplePoints[i].y, GRP_SMP_RAD);
}
// dc_blt.BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dc, 0, 0, SRCCOPY);
dc_blt.BitBlt(theGraph.x1,theGraph.y1,theGraph.width, theGraph.height, &dc, 0, 0, SRCCOPY);
}
I will need to change the origins of the viewport a number of times and my guess is that this could be one of the reasons for the error. Any suggestions will be welcome.
This is what my output look like without double buffering
This is what it looks like with my attempt at double buffering
In this case, a general solution is 'double buffering'.
The principle is that it creates a compatible memory dc for drawing in advance, and when drawing is ended, it outputs on screen dc.
A code sample is below.
//in OnPaint() function
CPaintDC dc(this);
CDC dcMem;
CBitmap bmpDC;
CRect rcClient;
GetClientRect(&rcClient);
dcMem.CreateCompatibleDC(pDC);
bmpDC.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());
dcMem.SelectObject(&bmpDC);
CRect rect(0, 0, 100, 200);
dcMem.Rectangle(rect);
dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);
A couple of references are below.
introduction
another reference
I hope this will help you a little.
Try the CMemDC MFC class.
In your OnPaintFunction you would have this:
CPaintDC DC(this);
CMemDC mDC(&DC, this);
// now use mDC instead of DC
Also look here fore more samples and explanations.