Search code examples
c++trigonometryangle

Why are the angles calculated in c++ not accurate?


I wanted to write a turtle in c++, but the angles at the turn are not accurate.

I tried to create a Koch curve, but the result was bad

Hereis a larger picture of this, it looks like the angles are wrong

This is my program:

#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "turtle.h"

#define MAX_LOADSTRING 100

// Global Variables:
#define HIBA_00 TEXT("Error:Program initialisation process.")

HINSTANCE hInstGlob;
int OwniCmdShow;
char szClassName[] = "WindowsApp";
HWND Form1;
LRESULT CALLBACK WndProc0(HWND, UINT, WPARAM, LPARAM);

RECT rc;
HDC hdcMem;
HBITMAP hbmMem, hbmOld;
HBRUSH hbrBkGnd;
HDC hdc;
PAINTSTRUCT ps;

void DB_prepare_puffer(void);
void DB_start_drawing(void);
void DB_end_drawing(void);


void draw(void);
void screen_clear(void);
void print(int n);


int depth = 4;
float length = 1000;
turtle t;



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("StdWinClassName");
    MSG msg;
    WNDCLASS wndclass0;
    OwniCmdShow = iCmdShow;
    hInstGlob = hInstance;

    wndclass0.style = CS_HREDRAW | CS_VREDRAW;
    wndclass0.lpfnWndProc = WndProc0;
    wndclass0.cbClsExtra = 0;
    wndclass0.cbWndExtra = 0;
    wndclass0.hInstance = hInstance;
    wndclass0.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass0.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass0.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass0.lpszMenuName = NULL;
    wndclass0.lpszClassName = TEXT("WIN0");

    if (!RegisterClass(&wndclass0))
    {
        MessageBox(NULL, HIBA_00, TEXT("Program Start"), MB_ICONERROR); return 0;
    }

    Form1 = CreateWindow(TEXT("WIN0"),
        TEXT("Form1"),
        (WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX),
        0,
        0,
        1920,
        1050,
        NULL,
        NULL,
        hInstance,
        NULL);
    DB_prepare_puffer();

    ShowWindow(Form1, OwniCmdShow);
    UpdateWindow(Form1);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc0(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc_lokal;
    PAINTSTRUCT ps_lokal;

    switch (message) {
    case WM_CREATE:
        break;
    case WM_MOUSEMOVE:
        break;
    case WM_ERASEBKGND:
        return (LRESULT)1;
        break;
    case WM_PAINT:
        hdc_lokal = BeginPaint(hwnd, &ps_lokal);
        EndPaint(hwnd, &ps_lokal);
        t.init();
        draw();
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcW(hwnd, message, wParam, lParam);
        break;
    }
    return NULL;
}

void DB_prepare_puffer(void)
{
    GetClientRect(Form1, &rc);
    hdc = GetDC(Form1);
    hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
}

void DB_start_drawing(void)
{
    GetClientRect(Form1, &rc);
    hdc = GetDC(Form1);
    BeginPaint(Form1, &ps);
    hdcMem = CreateCompatibleDC(hdc);
    hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
    hbrBkGnd = CreateSolidBrush(RGB(255, 255, 255));
    FillRect(hdcMem, &rc, hbrBkGnd);
    DeleteObject(hbrBkGnd);
}

void DB_end_drawing(void)
{
    BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, hbmOld);
    DeleteDC(hdcMem);
    EndPaint(Form1, &ps);
}

void draw(void)
{
    DB_start_drawing();
    screen_clear();
    int i = 0;
    depth = 5;
    length = 1200;
    while (i < depth) {
        length = length / 3;
        i++;
    }
    t.right(270);
    print(depth);
    DB_end_drawing();
}
//************************
//clear screen
//************************
void screen_clear(void)
{
    HBRUSH hBrush;
    RECT rect;
    HDC hdc;
    hdc = hdcMem;
    hBrush = CreateSolidBrush(RGB(255, 255, 255));
    SelectObject(hdc, hBrush);
    SetRect(&rect, 0, 0, 1500, 900);
    FillRect(hdc, &rect, hBrush);
    DeleteObject(hBrush);
}
void print(int m) {
    int n = m;
    if (n == 0) {
        t.forward(length, hdcMem);
    }
    if (n != 0){
        n -= 1;
        print(n);
        t.left(60);
        print(n);
        t.right(120);
        print(n);
        t.left(60);
        print(n);
    }
}

this is the turtle.h file:

#pragma once
#define _USE_MATH_DEFINES
#include "resource.h"
#include <windows.h>
#include <cmath>

class turtle {
public:
    void init();
    void right(double _angle);
    void left(double _angle);
    void forward(int distance, HDC hdc);
    double angle = 0;
    POINT pos;
protected:
private:
};

And this is the turtle.cpp:

#pragma once
#include "turtle.h"

void turtle::init()
{
    pos.x = 40;
    pos.y = 800;
    angle = 0;
}
void turtle::left(double _angle) {
    angle -= _angle;
}
void turtle::right(double _angle) {
    angle += _angle;
}
void turtle::forward(int distance, HDC hdc) {
    MoveToEx(hdc, pos.x, pos.y, NULL);
    double cos_angle = cos(angle * M_PI / (double)180);
    double sin_angle = sin(angle * M_PI / (double)180);
    POINT endpoint;
    endpoint.x = (0 - (double)distance * sin_angle) + pos.x;
    endpoint.y = (0 + (double)distance * cos_angle) + pos.y;
    LineTo(hdc, endpoint.x, endpoint.y);
    pos = endpoint;
}

In Python, however, this code worked (essentially the same as the c++ code):

from turtle import *

color('blue', 'white')
speed(100000000)
penup()
back(600)
pendown()
begin_fill()
depth = 0
length = 300
i = 0

def print(n):
    if n == 0:
        forward(length )
    if n != 0:
        n -= 1
        print(n)
        left(60)
        print(n)
        right(120)
        print(n)
        left(60)
        print(n)


i = 0
depth = 5
length = 300
while i < depth:
    length = length / 3
    i += 1

print(depth)

(Result)

I hope you can help me. Thanks


Solution

  • It will work with this code because the previously calculated position is stored more accurately. turtle.cpp:

    #pragma once
    #include "turtle.h"
    
    void turtle::init()
    {
        pos.x = 40;
        pos.y = 800;
        angle = 0;
    }
    void turtle::left(double _angle) {
       angle -= _angle;
     }
    void turtle::right(double _angle) {
        angle += _angle;
    }
    void turtle::forward(double distance, HDC hdc) {
        MoveToEx(hdc, pos.x, pos.y, NULL);
        double cos_angle = cos(angle * M_PI / (double)180);
        double sin_angle = sin(angle * M_PI / (double)180);
        DPOINT endpoint;
        endpoint.x = (0 - distance * sin_angle) + pos.x;
        endpoint.y = (0 + distance * cos_angle) + pos.y;
        LineTo(hdc, endpoint.x, endpoint.y);
        pos = endpoint;
    }
    

    And insert this code to turtle.h: `

    typedef struct DPOINT {
        double x;
        double y;
    };
    

    `

    And change the 'pos' variable type to 'DPOINT'