I'm trying to build custom line caps in GDI+ (C++), and I can't get it to draw a filled cap, while unfilled caps draw fine.
I set up a closed polygon path, create a CustomLineCap with the path as the first parameter (fillPath parameter), and call SetCustomStartCap on the pen:
std::vector<Gdiplus::Point> pathPoints =
{
Gdiplus::Point(20,0),
Gdiplus::Point(0,20),
Gdiplus::Point(-20,0),
Gdiplus::Point(20,0)
};
Gdiplus::GraphicsPath path;
path.AddPolygon(&pathPoints[0], 4);
Gdiplus::CustomLineCap startCap(&path, nullptr);
Gdiplus::CustomLineCap endCap(nullptr, path.Clone());
m_Pen.SetCustomStartCap(&startCap);
m_Pen.SetCustomEndCap(&endCap);
I've read comments that it might have to do with the point order, or if the path is definitely closed. I've tried having the points both clockwise and counter-clockwise, but it didn't seem to help.
Can anyone spot if I'm doing something obviously wrong, or maybe I'm missing something?
Aside from the order of the points, I think there's also a requirement that the shape must intersect the negative y-axis, that is the line itself. So if you create your polygon like this
std::vector<Point> pathPoints =
{
Gdiplus::Point(20,-1),
Gdiplus::Point(0,19),
Gdiplus::Point(-20,-1)
};
then you'll have a line cap with the desired shape and size, but it will overlap the line a bit.
Alternatively, if you want arrowheads specifically, take a look at AdjustableArrowCap. Just set the isFilled property to TRUE and you're good to go. Or you can just use Pen's SetStartCap/SetEndCap methods with the LineCapArrowAnchor parameter, but then you probably can't customize your arrow.
Related
I am trying to rotate am image around its origin(center) in QT using QWidgts in C++. I experimented a lot of things here, but no matter what I do, the image keeps rotating around some arbitrary position I have no clue of. Kindly, help me out here. I am new to QT.
void gaugeWithRedZoneImage::rotate()
{
QPixmap pixmap(*gaugeMainScreen->pixmap());
QMatrix rm;
rm.translate(0, 0);
rm.rotate(-360);
pixmap = pixmap.transformed(rm);
gaugeMainScreen->setPixmap(pixmap);
/*QTransform rotate_disc;
rotate_disc.translate(pixmap.width()/2.0 , pixmap.height()/2.0);
rotate_disc.rotate(-60);
rotate_disc.translate(-(pixmap.width()/2.0) , -(pixmap.height()/2.0));
pixmap = pixmap.transformed(rotate_disc);
gaugeMainScreen->setPixmap(pixmap);*/
}
Form the documentation of QPixmap::transformed():
The transformation transform is internally adjusted to compensate for unwanted translation; i.e. the pixmap produced is the smallest pixmap that contains all the transformed points of the original pixmap.
This means that the method ensures no clipping takes place by appending the canvas. No matter what your rotation center was, the automatic extension of canvas will almost always result in a perceived shift.
Image examples might help to further diagnose the problem.
As ypnos said, your problem isn't the rotation center. When you rotate your image, its width and height will most likely change and no longer fit your container (gaugeMainScreen) dimensions.
You have some possibilities to overcome this problem. One of them is to set your container to scale its contents (you can use the method setScaledContents()). In this case, you have to keep the original image around and use it whenever you apply a rotation, otherwise your image will appear increasingly smaller.
So I'm working on a project for a class and I'm still trying to figure out how to go about doing something.
I am making a game where there is a board of squares or hexagons, they are either black or white, each being a state of being "Flipped", and when you click one square/hexagon, it flips all the adjacent shapes too.
Here is an image of what I am aiming to create.
Assignment images
I have gotten it running with squares, but now I need to do it with Hexagons. With the squares I registered a mouseclick as being within a square parameters of the x and y location of the click, and the state changes are assigned to a list of values assigned similarly to how the shapes were assigned within a list.
I will include a quick recording of the square program running in a folder I'm going to link.
Now, I believe I can't apply this kind of system to hexagons since they don't really line up like the squares did.
So how would I go about making a click register within a single hexagon on a grid? I have already drawn out the grid, but I am stuck on what to do to register a click to allow a hexagon to change it's state from un-flipped to flipped. I'm pretty sure I know what to do for the state change itself, but I don't know how to go about this, would it involve something with making a separate Class or something? I would appreciate any help with this.
I'll put a dropbox link here for the progress I made so far, and a pdf manual for graphics.py.
Dropbox: Python files
You can view the python code in your web-browser with dropbox too, I don't really want to fill this page pull of an entire thing of code..
Any help and feedback would be wonderful, thank you c:
so, TL;DR: How do you register a click within a polygon shape in python that allows it to change a value (within a list?) and change its visual appearance.
Just for the general side of your question, you can use a test to check if a point (x, y) is inside a polygon (formed by a list of x, y pairs).
Here's one such solution: http://www.ariel.com.au/a/python-point-int-poly.html
# determine if a point is inside a given polygon or not
# Polygon is a list of (x,y) pairs.
def point_inside_polygon(x,y,poly):
n = len(poly)
inside =False
p1x,p1y = poly[0]
for i in range(n+1):
p2x,p2y = poly[i % n]
if y > min(p1y,p2y):
if y <= max(p1y,p2y):
if x <= max(p1x,p2x):
if p1y != p2y:
xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
if p1x == p2x or x <= xinters:
inside = not inside
p1x,p1y = p2x,p2y
return inside
This can be used in a way that is quite symmetrical to your drawing code, as you also form polygons in the same way for drawing as you would to test to see if the cursor is inside a hex.
You can modify the above implementation also to work with this Point type you are using to draw the polygons.
The rest you should be able to figure out, especially considering that you managed the input handling and drawing for the square grid.
When my programm start, it must display a circle on a background. Also i must controll all displaying circles. I use class VertexController and class Vertex for that purpose. In Vertex i have constructor:
Vertex::Vertex(const ci::Vec2f & CurrentLoc){
vColor = Color(Rand::randFloat(123.0f),Rand::randFloat(123.0f),Rand::randFloat(123.0f));
vRadius = Rand::randFloat(23.0f);
vLoc = CurrentLoc;
}
and in VertexController i have
VertexController::VertexController()
{
Vertex CenterVertex = Vertex(getWindowCenter());
CenterVertex.draw(); // function-member draw solid circle with random color
}
and in setup{} method i wrote
void TutorialApp::setup(){
gl::clear(Color(255,204,0));
mVertexController=VertexController();
}
Unfrtunatelly, my way didnt work.I see only background.
So the main question - in CINDER_APP_BASIC drawing possible only in draw{},update{},setup{} directly? If yes, advise a solution, else say where is my fail.
this line of code does not make any sense to me:
mVertexController=VertexController();
Anyways, you should use draw() function just for drawing circles to window. This it why by default there is gl::clear(Color(0,0,0)); to clear background and start drawing new frame from scratch (this is the way drawing in OpenGL, used by default in Cinder, works).
I suggest to use Vector container for storing all circles (this way you can add and remove circles on the fly with some effort), add the first one in VertexController constructor, and make separate function VertexController::draw() to draw all circles using for loop.
Sorry I'm a bit new with SDL and C++ development. Right now I've created a tile mapper that reads from my map.txt file. So far it works, but I want to add editing the map now.
SDL_Texture *texture;
texture= IMG_LoadTexture(G_Renderer,"assets/tile_1.png");
SDL_RenderCopy(G_Renderer, texture, NULL, &destination);
SDL_RenderPresent(G_Renderer);
The above is the basic way I'm showing my tiles, but if I want to go in and change the texture in real time it's kind of buggy and doesn't work well. Is there a method that is best for editing a texture? Thanks for the help I appreciate everything.
The most basic way is to set up a storage container with some textures which you will use repeatedly; for example a vector or dictionary/map. Using the map approach for example you could do something like:
// remember to #include <map>
map<string, SDL_Texture> myTextures;
// assign using array-like notation:
myTextures["texture1"] = IMG_LoadTexture(G_Renderer,"assets/tile_1.png");
myTextures["texture2"] = IMG_LoadTexture(G_Renderer,"assets/tile_2.png");
myTextures["texture3"] = IMG_LoadTexture(G_Renderer,"assets/tile_3.png");
myTextures["texture4"] = IMG_LoadTexture(G_Renderer,"assets/tile_4.png");
then to utilise a different texture, all you have to do is use something along the lines of:
SDL_RenderCopy(G_Renderer, myTextures["texture1"], NULL, &destination);
SDL_RenderPresent(G_Renderer);
which can be further controlled by changing the first line to
SDL_RenderCopy(G_Renderer, myTextures[textureName], NULL, &destination);
where textureName is a string variable which you can alter in code in realtime.
This approach means you can load all the textures you will need before-hand and simply utilise them as needed later, meaning there's no loading from file system whilst rendering:)
There is a nice explanation of map here.
Hopefully this gives you a nudge in the right direction. Let me know if you need more info:)
I have a CCSprite which gradually needs to be exhausted linearly from one end, lets say from left to right.For this purpose ,I am trying to change the textureRect property of the sprite so that the part that got exhausted from one end is 'outside' the displaying frame of the sprite.
I did this sort of thing before with a sprite that gets loaded from a spritesheet.And it worked perfectly.But I created this CCSprite using CCRenderTexture and by changing the textureRect property,the entire sprite gets disappeared.
The first image is the original CCSprite which I get from CCRenderTexture.The second image shows what I want to achieve.The black dotted rectangular portion of the Sprite needs to be omitted out.Only the blue dotted portion of the sprite needs to be displayed.Essentially,this blue dotted rectangle is my textureRect.
Is there any way how I could make my sprite reduce from one end.
Also is there any difference between a sprite created normally,and one created using CCRenderTexture.
I have done similar thing like this before using some low-level hack.
There is a work around solution if you use CCProgressTimer, that's very easy and I think it should be enough for your examples.
But you said in comment that you have some special requirements like "exhaust it from both the ends at once" then some low-level hack is needed. My solution from my last object is:
1) Get the texture image's raw data. In cocos2d you can use CCRenderTexture and in cocos2d-x you can use CCImage.
2) CCRenderTexture has a method of - (BOOL) saveToFile: (NSString *) name
format: (tCCImageFormat) format
. You can read its source code then try to save it into an 2D array instead like byte raw[1024][768]. Each element in this array represents one pixel on your picture(the type may not be byte, I'm not sure, nearly forget the details). The format MUST BE PNG since transparency will be needed.
3) Modify raw data directly, set pixel's transparency to 0x0 which you want it to disappear.
4) Re-initialize a CCRenderTexture using picture data you modified.
I can't provide the code directly since is a trade secret and core part of one of my projects. But I can share you my solution. You also need some knowledge about how PNG file works. Read:
https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
Turns out I was making a silly mistake.While supplying values to the textureRect(CGRect),I was actually setting the textureRect.origin.y to the height of the texture which made my textureRect go beyond(above) the texture area.This explains why they were disappearing.