I am processing 2-dimensional shapes in ruby. I have a Point class with x and y attribute, and a Line class which has two end points. Later in the process chain, I often want to identify and process vertical lines slightly differently from horizontal lines, even though both can occur in the same set of Lines. I have mix-ins to do the processing, but often I find the method has something like
if l.vertical?
l.do_something_with_y_coordinate
elsif l.horizontal?
l.do_something_with_x_coordinate
end
I see this pattern quite frequently and I do not like the repetition. I could try to avoid it by identifying instances of Line that are vertical and creating a VerticalLine class, and a HorizontalLine class, but that feels more like .Net than ruby and does not reduce the duplication, just encapsulates it.
Another way might be to have a direction method that returns :x or :y and then a method to "do_something_with direction".
Does anybody else have any suggestions about how to refactor?
It's not "more like .Net", it's more like proper object-oriented encapsulation. If you learned that via .Net, that's fine, but it's a very general approach that dates back decades before .Net or Ruby ever existed.
There's three ways to tackle this problem:
Use an if to split behaviour.
Use subclasses to implement the specific behaviour.
Generalize your code so it doesn't matter if it's vertical or horizontal, the same math is applied in both cases.
In the third case imagine having vector(s) or a matrix which describes the geometry you're manipulating. For example, [0, 1] could represent a vertical line going up, or [-1, 0] a line going to the left depending on your coordinate system. Each iteration you just add that to your base point. The very idea of horizontal or vertical melts away.
In the concrete case I see three suggestions:
1.) Define accessors which map to x and y depending on the two cases:
def s=(value)
if horizontal
x = value
else
y = value
end
end
def t=(value)
if horizontal
y = value
else
x = value
end
end
With this you can delegate to the "right" field dynamically.
2.) Convert your horizontal cases into vertical ones by rotating, then performing the operation and then rotating it back.
3.) Using another representation that doesn't use x and y such as polar coordinates where your differentiates vanishes.
Related
I am working on a image search algorithm that finds certain shapes of certain colors; to save time I only register half of the shape's perimeter in 2 distinct sets, one for the rows and one for the columns used by the shape. The idea is that whenever I find a point which has the target color, I then check if this point's row and column are in a master set (which have both the previous sets); if they are I skip it, if they are not then I initialize 2 recursive fuctions that register the first row and the first column of the shape.
Since it's for a school project, my images are specially tailored
and the code would be
for y in range(height):
for x in range(width):
if img[y][x] == target:
if y in master_set and x in master_set:
continue
else:
row = set()
column = set()
flood_fillv2_y(img,x,y,target,column)
flood_fillv2_x(img,x,y,target,row)
row=frozenset(row)
column=frozenset(column)
master_set.add(row)
master_set.add(column)
The idea then is to check the len of master_set to see how many shapes I have, but as I said what I get is that y and x are never in the master set so it keeps doing it for all points of the shape, resulting in a wrong number.
It's hard to give a good answer without seeing the whole code, but I can give a guess:
master_set.add(row) literally adds the frozenset row to the master_set, but you probably want all elements from the set to be added to master_set. Take a look at the update() method of sets.
Does this help?
considering this basic case, one may expect the coordinates of the layer to be updated... but they would not.
Instead, there is the possibility of remembering the starting point, compute the mouse offset and then update the coordinates, like in this test but... the effect is quite extreme.
Expected : point x1,y1 is static
Result : point x1,y1 moves incredibly fast
If setting coordinates to constant, the drag remains the same.
The main problem here is that drag action applies to the whole layer.
Fix : apply the modification at the end of the drag, like in this snippet.
But it is relatively ugly. Anyone has a better way to
get on the run the actual coordinates of the points of the line
manage to keep a point of the line static while the others are moving
Looking forward your suggestions,
In order to maintain the efficiency of dragging layers, jCanvas only offsets the x and y properties for any draggable layer (including paths). Therefore, when dragging, you can compute the absolute positions of any set of path coordinates using something along these lines:
var absX1 = layer.x + layer.x1;
var absY1 = layer.y + layer.y1;
(assuming layer references a jCanvas layer, of course)
I want to plot only one simple set of data. For example, my plot command could be :
x = (1:10);
y = ones[1,10];
plot(x,y);
In fact, the y data set could have been generated by a previous code, depending on several parameters. I want to print the name of every parameters and there values outside the graph, at the right of it, as if it were a legend. My problem is that I have several parameters to print, but only one set of data.
I tried to do this by the text or legend functions, but it never fit completly my needs.
Could you help me please ?
I think this code should help you out. Its probably easiest to split your figure into two axes, the right one just to hold text:
x = rand(1,10);
y = rand(1,10);
figure % makes your figure
axes('Position', [0.05,0.05,0.45,.9]) % makes axes on left side of your figure
scatter(x,y)
axes('Position', [0.55,0,1,1],'ytick',[],'xtick',[]) %make axes on left side of your figure, turns of ticks
text(0.05,0.85,{'Parameter 1: blah blah';'Parameter 2: bloop bloop';'Parameter 3: ....'},'Interpreter','Latex')
Play around with the numbers in the brackets to resize things as you like.
I am working on a drawing program and am trying to figure out the best way to imitate the 'magnet' behavior found in applications such as Omnigraffle. The idea is: as a line is drawn between two objects (visual objects on screen, not OOP objects), as the line from the first object approaches the second, a 'magnet' or 'node' on the second will highlight or the second object will highlight.
I was looking to keep all of the on-screen objects in an array and using notifications to send that array the position of the end of the line as it moves. This way, I could have each object do its own comparison and say "Hey, I have a node near the line, I think I'll light it up".
I was also wondering if it would be the same approach if I wanted to have two objects, say boxes for instance, that would snap together, side by side, when they came into proximity with each other. This way, it would be possible to line up the boxes on the same X or Y coordinate
I'm not concerned about the highlighting or having the line snap to the position of a node, I'm just wondering about the best way to implement the 'edge proximity detection' part of this problem.
If you are using CGRect types I'd suggest you use the two functions CGRectInset() and CGRectIntersectsRect()
Use CGRectInset() to expand one or both rects and then use CGRectIntersectsRect() to see if you have a match. You could also use (at the same time) CGRectIntersectsRect() on the original rects to see that you only have are close and not covering each other.
Greetings,
I'm working on a game project that uses a 3D variant of hexagonal tile maps. Tiles are actually cubes, not hexes, but are laid out just like hexes (because a square can be turned to a cube to extrapolate from 2D to 3D, but there is no 3D version of a hex). Rather than a verbose description, here goes an example of a 4x4x4 map:
(I have highlighted an arbitrary tile (green) and its adjacent tiles (yellow) to help describe how the whole thing is supposed to work; but the adjacency functions are not the issue, that's already solved.)
I have a struct type to represent tiles, and maps are represented as a 3D array of tiles (wrapped in a Map class to add some utility methods, but that's not very relevant).
Each tile is supposed to represent a perfectly cubic space, and they are all exactly the same size. Also, the offset between adjacent "rows" is exactly half the size of a tile.
That's enough context; my question is:
Given the coordinates of two points A and B, how can I generate a list of the tiles (or, rather, their coordinates) that a straight line between A and B would cross?
That would later be used for a variety of purposes, such as determining Line-of-sight, charge path legality, and so on.
BTW, this may be useful: my maps use the (0,0,0) as a reference position. The 'jagging' of the map can be defined as offsetting each tile ((y+z) mod 2) * tileSize/2.0 to the right from the position it'd have on a "sane" cartesian system. For the non-jagged rows, that yields 0; for rows where (y+z) mod 2 is 1, it yields 0.5 tiles.
I'm working on C#4 targeting the .Net Framework 4.0; but I don't really need specific code, just the algorithm to solve the weird geometric/mathematical problem. I have been trying for several days to solve this at no avail; and trying to draw the whole thing on paper to "visualize" it didn't help either :( .
Thanks in advance for any answer
Until one of the clever SOers turns up, here's my dumb solution. I'll explain it in 2D 'cos that makes it easier to explain, but it will generalise to 3D easily enough. I think any attempt to try to work this entirely in cell index space is doomed to failure (though I'll admit it's just what I think and I look forward to being proved wrong).
So you need to define a function to map from cartesian coordinates to cell indices. This is straightforward, if a little tricky. First, decide whether point(0,0) is the bottom left corner of cell(0,0) or the centre, or some other point. Since it makes the explanations easier, I'll go with bottom-left corner. Observe that any point(x,floor(y)==0) maps to cell(floor(x),0). Indeed, any point(x,even(floor(y))) maps to cell(floor(x),floor(y)).
Here, I invent the boolean function even which returns True if its argument is an even integer. I'll use odd next: any point point(x,odd(floor(y)) maps to cell(floor(x-0.5),floor(y)).
Now you have the basics of the recipe for determining lines-of-sight.
You will also need a function to map from cell(m,n) back to a point in cartesian space. That should be straightforward once you have decided where the origin lies.
Now, unless I've misplaced some brackets, I think you are on your way. You'll need to:
decide where in cell(0,0) you position point(0,0); and adjust the function accordingly;
decide where points along the cell boundaries fall; and
generalise this into 3 dimensions.
Depending on the size of the playing field you could store the cartesian coordinates of the cell boundaries in a lookup table (or other data structure), which would probably speed things up.
Perhaps you can avoid all the complex math if you look at your problem in another way:
I see that you only shift your blocks (alternating) along the first axis by half the blocksize. If you split up your blocks along this axis the above example will become (with shifts) an (9x4x4) simple cartesian coordinate system with regular stacked blocks. Now doing the raytracing becomes much more simple and less error prone.