I need to add a batch of arrow annotations to an image, I know all the start and end points of the arrows.
And I've put them into an image (2 columns, many rows) which I used as a data sheet, how to realize it in script?
I noticed that in the DM help manual that the line annotation has the attributes-- start point and end point.
But the function to create an arrow annotation jsut looks like this:
Component NewArrowAnnotation( Number top, Number left, Number bottom, Number right )
Does that mean the number top and left define the start point, number bottom and right the end point?
I also need to change the color of the annotations, and add some text next to them (either side is OK, but please show me how to control it).
What isn't always clear from the current documentation is that annotations belong to the component object. You therefore find all required commands documented in the component section of the help documentation.
Note that also imageDisplays are themselves a subclass of the component object, so you can add "annotations" (components) to "imageDisplay" (components) using the ComponentAddChild... commands.
A script to add a simple arrow-annotation (pointing at 200/200) can therefore look like the following:
image test := RealImage( "Test", 4, 512, 512 )
test.ShowImage()
ImageDisplay disp = test.ImageGetImageDisplay(0)
component arrow = NewArrowAnnotation(100,100,200,200)
arrow.ComponentSetForegroundColor( 0, 1, 1 )
disp.ComponentAddChildAtEnd( arrow )
Related
I've followed "Procedural Generation in Godot: Dungeon Generation" by KidsCanCode #https://www.youtube.com/watch?v=o3fwlk1NI-w and find myself unable to debug the current problem.
This specific commit has the code, but I'll try to explain in more detail bellow.
My main scene has a Camera2D node, a generic Node2D calles Rooms and a TileMap, everything is empty.
When the script starts, it runs a
func make_room(_pos, _size):
position = _pos
size = _size
var s = RectangleShape2D.new()
s.custom_solver_bias = 0.5
s.extents = size
$CollisionShape2D.shape = s
A few times and it fills $Rooms using .add_child(r) where r is a instance of the node that has the make_room() function. It will then iterate over $Rooms.get_children() a few times to create a AStar node to link all the rooms:
The magic comes when make_map() is called after afterwards, it fills the map with non-walkable blocks and then it carves the empty spaces, which works fine too:
There is a find_start_room() that is called to find the initial room, it also sets a global variable to the Main script start_room, which is used to write 'Start' on the map using draw_string(font, start_room.position - Vector2(125,0),"start",Color(3,4,8))
When I hit 'esc' it runs this simple code to instance the player:
player = Player.instance()
add_child(player)
player.position = start_room.position + Vector2(start_room.size.x/2, start_room.size.y/2)
play_mode = true
The problem comes when spawning the player. I tried doing some 'blind' fixing, such as adding or subtracting a Vector2(start_room.size.x/2, start_room.size.y/2) to player.position to see if I could make it fall within the room, to no avail.
Turning to the debugger didn't help, as the positions expressed by the variable inspectors don't seem to mean anything.
I tried implementing a simple 'mouse click print location':
print("Mouse Click/Unclick at: ", event.position)
print("Node thing",get_node("/root/Main/TileMap").world_to_map(event.position))
And also a 'start_room' print location:
print(get_node("/root/Main/TileMap").world_to_map(start_room.position))
And a when player moves print location, written directly into the Character script:
print(get_node("/root/Main/TileMap").world_to_map(self.position))
Getting results like the ones bellow:
Mouse Click/Unclick at: (518, 293)
Node thing(16, 9)
(-142, 0)
(-147, -3)
So, the player doesn't spawn on the same position as the start_room and the mouse position information is not the same as anything else.
Why is the player now spawning correctly? How can I debug this situation?
EDIT1: User Theraot mentioned about how the RigidBody2D is doing some weird collisions, and from what I understood, changing their collision behavior should fix the whole thing.
There's a section on the code that -after generating the random rooms- it removes some of the rooms like this:
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room_positions.append(Vector3(room.position.x, room.position.y, 0))
From what I understand, if the room is randomly selected it will be deleted using queue_free() OR it will be appended to a room_positions for further processing. This means if I shift all the rooms to a different collision layer, the player/character instance would be alone with the TileMap on the same collision layer.
So I just added a simple room.collision_layer = 3 changing this section of the code to
for room in $Rooms.get_children():
if randf() < cull:
room.queue_free()
else:
room.mode = RigidBody2D.MODE_STATIC
room.collision_layer = 3
room_positions.append(Vector3(room.position.x, room.position.y, 0))
It doesn't seem to have changed anything, the player still spawns outside the room.
Do you see the rooms spread outwards?
You didn't write code to move the rooms. Sure, the code gives them a random position. But even if you set their position to Vector2.ZERO they move outwards, avoiding overlaps.
Why? Because these rooms are RigidBody2D, and they do push other physics objects. Such as other rooms or the player character.
That's the problem: These rooms are RigidBody2D, and you put your KinematicBody2D player character on top of one of them. The RigidBody2D pushes it out.
The tutorial you followed is exploiting this behavior of RigidBody2Ds to spread the rooms. However you don't need these RigidBody2D after you are done populating your TileMap.
Instead, you can store the start position in a variable for later placing the player character (you don't need offsets - by the way - the position of the room is the center of the room), and then remove the RigidBody2Ds. If you want to keep the code that writes the text, you would also have to modify it, so it does not fail when the room no longer exists.
Alternatively, you can edit their collision layer and mask so they don't collide with the player character (or anything for that matter, but why would you want these RigidBody2Ds that collide with nothing?).
Addendum post edit: Collision layers and mask don't work as you expect.
First of all, the collision layer and mask are flags. The values of the layers are powers of two (1, 2, 4, 8...). So, when you set it to 3, it is the layer 1 plus the layer 2. So it still collides with a collision mask of 1.
And second, even if you changed the collision layer of the rooms to 2 (so it does not match the collision mask of 1 that the player character has). The player character still has a layer 1 which match the collision mask of the rooms.
See also the proposal Make physics layers and masks logic simple and consistent.
Thus, you would need to change the layer and mask. Both. in such way that they don't collide. For example, you can set layer and mask to 0 (which disable all collisions). The algorithm that populates the TileMap does not use the layer and mask.
I wrote a little program that copies the frame and position of a ROI from an image to an other image of the same size.
What I want to do now is to connect the two ROIs in way that when I move one ROI the other one is moving accordingly.
On Dave's mitchell DM scripting website, I found that he used the function ConnectObject. but he does not explain how it works.
I read the DM3's documentation and I couldn't find any information about that function.
There are two concepts here which would work. You can use one of two methods:
1) Use "ConnectObject" to attach some functionality to when a ROI is moved, i.e. when you move ROI 1 it "triggers" code which you can use to update other rois.
2) Use "ImageDisplayListeners" to attach functionality to when any ROI on a specific imageDisplay is moved,
i.e. when a ROI an image A is moved it triggers code which you can use to update other rois.
You will find example code in this answer.
For simple things there is another option:
Adding the identical ROI to more than one image-display:
In this case, the ROIs are "linked" automatically, because they really are only a single object in memory (but displayed on two displays.) Changing one will change the other.
However, this linkage is "lost" if you save/load the images, because when you load the image, all ROIs (in memory) are newly created. Here is some simple example code:
image img1, img2
GetTwoLabeledImagesWithPrompt("Select two images of same size.", "Select", "Source", img1, "Destination", img2 )
imageDisplay disp1 = img1.ImageGetImageDisplay( 0 )
imageDisplay disp2 = img2.ImageGetImageDisplay( 0 )
number nR = disp1.ImageDisplayCountROIs()
for ( number i = 0; i<nR; i++ )
{
ROI theROI = disp1.ImageDisplayGetROI(i)
disp2.ImageDisplayAddROI(theROI)
}
I'm working with a jsx script in Photoshop that resizes images to a specific size. The resolution is set at 200 dpi. After running the script, I can check this under Image > Image Size.
Problem is, depending on the image, it initially tends to show the resolution in dots/cm instead of dots/inch. The number itself is correct either way, but I'd like to see it mentioned there as the latter. Is there a way to realize this in JSX?
Thanks!
J
The easy way is to open your Info Panel by going to Window > Info, and then click on the x/y coordinates dropdown in the Info Panel and select inches. The dropdown is the + toward the lower-left of the panel, with the little down arrow at the bottom right of the + symbol (The plus is actually an x axis and y axis representing a coordinate plane). After that, when you check under Image > Image Size, it should show you all information in inches instead of centimeters. This should also show you inches anywhere else you look in Photoshop's interface, too, such as the rulers.
An exception would be that when using selection tools, such as the marquee tool with a setting like "fixed size" selected, you can override the units setting by typing in another unit in the Width and Height sections at the top of the window. You can even mix and match units, making a precise selection that is, for example, exactly 250 pixels (px in the Width setting) by 30 points (pt in the Height setting). And when you check your image size, it should still show you results in inches.
And finally, to answer your question as it was asked, the following code will change your rulerUnits preference without opening the Info Panel.
#target Photoshop
preferences.rulerUnits = Units.INCHES;
Note that if you want to write other scripts, you can change the rulerUnits to whatever units the script calls for, and then at the end of the script put your units back the way you had them.
#target Photoshop
// Save the original rulerUnits setting to a variable
var originalRulerUnits = preferences.rulerUnits;
// Change the rulerUnits to Inches
preferences.rulerUnits = Units.INCHES;
//
// Do magical scripty stuff here...
//
// Restore the original setting
preferences.rulerUnits = originalRulerUnits;
// List of rulerUnits settings available
// Units.CM
// Units.INCHES
// Units.MM
// Units.PERCENT
// Units.PICAS
// Units.PIXELS
// Units.POINTS
When creating a nice slider using Mootools More 1.5.1 Slider class, I noticed that the 'knob' can be dragged too far to the right.
Consider this slider scenario:
|--|~|----------------|
I find I am able to do this:
|---------------------||~|
which is no good when the parent div has overflow:hidden set.
This occurs because the Drag object in the Slider class sets the left most x position ( limit.x[1] ) as the width of the passed in element (parent of the knob).
I would expect this limit to be the the element width minus the knob width.
I get the same problem whether the 'knob' is inside or outside the 'element' (above and below in the DOM).
The only way I could fix this was with a hack:
if(mySlider.drag.options.limit.x[1]===mySlider.element.getSize().x){
mySlider.drag.options.limit.x[1] -= mySlider.knob.getSize().x;
mySlider.drag.setOptions(mySlider.drag.options);
}
Check out this Fiddle (examples of broken and hacked).
Am I missing something here? Or should this be raised as a bug?
I have a Zedgraph textobj which I want to place always in the same x, y position (ASP.NET image). I noticed that the text doesn't always show in the same starting x position. It shifts depending on the text's length. I tried to have the text to have the same length by padding it with spaces. It helped a little but the result is not always consistent. I am using PaneFraction for coordType.
What's the proper method to have a piece of text to always show in the same x position. I am using textobj as a title because the native title property always shows up centered and I need my title be left aligned to the graph.
No, it does not depend on text lenght, however...
It depends on various other things:
Horizontal and vertical align of the text box (see: Location )
Current size of the pane. The font size is scaled dynamically to fit the changing size of the chart.
Counting proper positions to have TextObj (or any other object) always at the same place is quite hard. So you need avoid as much as you can any numbers/fractions in your location coordinates. ZedGraph sometimes calculates the true position in quite odd way then.
You haven't provided any code, so it's hard to tell if and where you made the mistake (if any). But, if I were you, I would do something like that:
TextObj fakeTitle = new TextObj("some title\n ", 0.0, 0.0); // I'm using \n to have additional line - this would give me some space, margin.
fakeTitle.Location.CoordinateFrame = CoordType.ChartFraction;
fakeTitle.Location.AlignH = AlignH.Left; // Left align - that's what you need
fakeTitle.Location.AlignV = AlignV.Bottom; // Bottom - it means, that left bottom corner of your object would be located at the left top corner of the chart (point (0,0))
fakeTitle.FontSpec.Border.IsVisible = false; // Disable the border
fakeTitle.FontSpec.Fill.IsVisible = false; // ... and the fill. You don't need it.
zg1.MasterPane[0].GraphObjList.Add(fakeTitle);
I'm using ChartFraction coordinates instead of PaneFraction (as drharris suggests) coordinates to have the title nicely aligned with the left border of the chart. Otherwise it would be flushed totally to the left side (no margin etc...) - it looks better this way.
But make sure you didn't set too big font size - it could be clipped at the top
Are you using this constructor?
TextObj(text, x, y, coordType, alignH, alignV)
If not, then be sure you're setting alignH to AlignH.Left and alignV to AlignV.Top. Then X and Y should be 0, 0. PaneFraction for the coordType should be the correct option here, unless I'm missing your intent.
Alternatively, you can simply download Zedgraph code, edit it to Left-align the title (or even better, provide an option for this, which should have been done originally), and then use it in production. Beauty of open source.