How to determine smallest height of vertical scrollbar? - cocoa

Other then creating a dummy NSScroller and incrementally decreasing it's height until usableParts returns 0, is there any easy way to determine what the minimum height of a vertical scrollbar should be so that usableParts will not return NSNoScrollerParts?
What I need to be able to do is limit the height of my window based, in part, on whether or not a vertical scrollbar will have usable parts.

Related

Fast algorithm to test if axis aligned rects cover another rect

We have axis aligned rect as: { top, left, width, height: number}
We want to test given:
a list of axis aligned rects rs
an axis aligned rect: r
if r is entirely covered by the union of rs.
What's the fastest way to do this?
What I have found is there are fast data structures to test intersections of rs and r (e.g. https://github.com/mourner/rbush), so I can first find what rects in rs intersect with r and then subtract from r all these rects, and see if you have any remained area. This seems to work well if rs has not much overlapping, because you don't end up with a lot of intersecting rects.
Any better solutions?
You can think of a scanline process.
Sort all rectangles by the ordinate of the top edge. Then move from top edge to top edge, keeping a list of "active rectangles" updated (i.e. all rectangles that cross the current horizontal).
Consider the horizontal extent covered by these rectangles between two successive horizontals, and check if they full cover the corresponding slice of the target rectangle.

Highest possible pyramid

I tried everything, but I still can't solve this problem without brute force:
I get N blocks with a known height and width. I can rotate them (height become width and width become height) and I have to build the tallest possible pyramid from them (of course I can change the order of blocks).
The problem is that you can't put a block of width X onto a block with width smaller than X.
EDIT:
The problem is, that you can't put a block onto a block of the same width.
Any ideas?
What I understand reading your problem statement and comments is that you want to build tallest pyramid with width from bottom to top in decreasing order.
If this is the case, then what we can do is simply the following steps:
Loop over blocks and swap width and height only if width > height.
Now, sort the array of blocks in decreasing order of width which is the order used for stacking blocks from bottom to top in pyramid.
Answer is summation of all heights.
Note: step -2 is only needed if you want to display order of blocks
from bottom to top in pyramid.

How to create horizontal rectangle that fills up or decreases color area depending on input value

I know there's a name for this, but I can't seem to think of it (or even provide a better title description.)
Image an empty horizontal rectangle - left edge has a value of 0, right edge has a value of 5. Now above it, there's a graph with an x-axis range of 0-5. When the plotting of the graph begins, the x-axis value is used as input to the horizontal rectangle in order to show, using a specific color, the area of the value.
Example: when input is given to the rectangle, the graph's x-axis value is 2.5. The rectangle now has half of it's area covered in red starting from the left edge. The value now is 3. Same idea, the area now stretches to "3".
It's a dynamic horizontal graph of sorts. Anywho, how do I go about creating this for iOS? Is there a class that's already built? Or do I just use rectangle drawing methods in a UIView subclass?
Thanks
update: here's an image of what I'm after: Bar

Locating "black rectangles" on an image - language independent

I am writing a small image analysis program just for fun. Image analysis has always fascinated me. I am trying to locate regions on a scanned document. These regions are going to be marked by clearly defined filled black rectangles (pre-printed on the page).
My problem is locating the rectangles. I know SIFT\SURF find "features" but I am trying to find something specific. Here is what I was thinking of doing. I am not sure if this is the "right" way or there is a better idea.
First off using some library I will turn the image into greyscale, perhaps a PGM since that is what I'm used to working with in school. For the analysis I first plan to run the image through a state of the art deskew algorithm in OpenCV or something else that I find. Once I have my deskewed image I will then threshhold it at some pretty high thresshold. The rectangles are going to be straight black hence me using a pretty high threshhold. I will then experimentally determine a good size black rectangle to slide across the image. While sliding my rectangle across the image I will determine the areas where the greatest percentage of pixles are the same. I will have a cutoff, say 90%. If 90% of the pixles contained in my window are black I must have found a rectangle. My reasoning is that a true black rectangle slid over something that is "pretty much" a black rectangle is most likely a black rectangle. Since I deskewed the image I can assume that the rectangles are straight up and down "enough". I can then track the (x,y) offsets where the rectangles are found on the image and mark them.
Would anyone suggest a better approach?
There are many approaches that might work. (One can easily come up with 10 or more approaches.)
Idea #1 - Canny edge detection; find rectangle fit to contours
cv::Canny
cv::findContours
cv::minAreaRect, or
cv::boundingRect might also work, if the deskewing works as advertised.
Idea #2 - Find all lines using Hough transform; Iterates through all regions created from line intersections.
Idea #3 - (Improvement on #2) Restrict the Hough transform to horizontal and vertical lines by pre-processing.
Idea #4 - Compute Horizontal and Vertical profiles on the entire image; find dips; iterate through all candidate regions.
This idea is based on the assumption that the black rectangles are large enough that they leave a "depression" in both the horizontal and vertical projection profiles, which would be detectable despite other noise objects in the image.
cv::reduce
With dim = 0 or 1 for reducing to a row or column respectively,
With CV_REDUCE_AVG flag
Apply cv::threshold to the horizontal and vertical projection profiles, separately.
For each profile now thresholded into zero/non-zero, find runs of zeroes. These are the possible row ranges and column ranges that could contain the dark rectangles.
For each combination of candidate row range and column range, calculate the average pixel value to decide if it is a true dark rectangle.
Idea #5 - Use integral image (summed area table) to quickly calculate the average pixel value in arbitrary rectangles
cv::integral
To compute the sum (and average) of a rectangle from an integral image, see the Wikipedia article on Summed Area Table
Preprocessing idea - use morphological dilation (or erosion) to "erase" things that cannot be the large continuous black box.
Preprocessing idea - use pre-processing to enhance horizontal and vertical edges; suppress edges in other directions.
I don't know if it is a better approach, but the first thing that came to mind would be a scan-line solution (assuming black or white pixels): I'd check each scanline from top to bottom. In each scanline I'd check each pixel from left to right. A "first" black pixel would be a possible upperleft corner of a rect. If there were enough following contiguous black pixels on the line to meet my desired minimum width, keep the [left, width] in a list of possible rects. Find all possible rect starts and widths on the line.
For a rect to stay in the list and grow in height, the next scanline would have to have the same [left, width] occurrence, otherwise the rect is finished (if its height meets my desired minimum height) or discarded or ignored as too short in height.
You can easily add logic for situations like two rectangles too close to one another vertically or horizontally. Overlapping rectangles would be trickier but still possible to detect with added code.
Here's some pseudocode:
for s := 1 to scanlinecount do
begin
pixel := 1
while pixel <= scanlinewidth do
if black(s, pixel) then // possible rect
begin
left := pixel
repeat
inc(pixel)
until (pixel > scanlinewidth) or white(s, pixel)
width := pixel - left
if width >= MINWIDTH then // wide enough
rememberrect(s, left, width) // bumps height if already in list
end
else inc(pixel)
end
Your list of found rects stores the starting scanline, leftmost pixel, width, and height for each rect found. The "rememberrect" routine checks each rect in the list:
rememberrect(currentline, left, width):
for r := 1 to rectlist.count do
if rectlist[r].left = left
& rectlist[r].width = width
& rectlist[r].y + rectlist[r].height = currentline then
begin // found rect continuing on scanline
inc(rectlist[r].height)
exit
end
inc(rectlist.count) // add new rect to list
rectlist[rectlist.count].left := left
rectlist[rectlist.count].width := width
rectlist[rectlist.count].y := currentline
rectlist[rectlist.count].height := 1
If the group of black pixels on the current scanline has the same leftmost pixel and width as a group on the previous scanline (you'll know they're vertically contiguous because the starting scanline of the rect in the list plus its height will equal the current scanline) then rememberrect bumps the height of the found and remembered rect by 1. Otherwise, remember the new rect with initial height 1.
After the last scanline you'll have a long list of rect candidates, many of them only 1 pixel high. Delete or ignore any rects in the list that aren't high enough. To avoid growing a long list of futile candidates: at the start of each scanline mark all rects found so far as "finished". If rememberrect grows an existing rect or adds a new rect, mark that rect as "grown". At the end of each scanline, any rect still marked as finished that isn't tall enough can be deleted from the list.

Graphviz ignores size attribute (A4 page)

Consider the following minimal example graph that should fit on an A4 page
digraph G{
size="8.3,11.7!" ratio=fill;
foo->bar;
}
Compile with neato -Tpdf -o min_ex.pdf min_ex.gv
The resulting pdf file has dimensions of 236mm x 115mm and not, as intended, 210mm x 297mm.
Graphviz ignores this attribute both for graphs that are smaller than the page (like this one) and the ones that have to be scaled down to fit.
I have tried any combinations of size and ratio attributes, I can't get the graph to be put on an A4 page with any of them.
So, what have I to specify that the graph is always put on an A4 page, regardless of its size?
Documentation:
size:
Maximum width and height of drawing, in inches. If only a single number is given, this is used for both the width and the height.
If defined and the drawing is larger than the given size, the drawing is uniformly scaled down so that it fits within the given size.
If size ends in an exclamation point (!), then it is taken to be the desired size. In this case, if both dimensions of the drawing are less than size, the drawing is scaled up uniformly until at least one dimension equals its dimension in size.
ratio
Sets the aspect ratio (drawing height/drawing width) for the drawing. Note that this is adjusted before the size attribute constraints are enforced. In addition, the calculations usually ignore the node sizes, so the final drawing size may only approximate what is desired.
If ratio is numeric, it is taken as the desired aspect ratio. Then, if the actual aspect ratio is less than the desired ratio, the drawing height is scaled up to achieve the desired ratio; if the actual ratio is greater than that desired ratio, the drawing width is scaled up.
If ratio = "fill" and the size attribute is set, node positions are scaled, separately in both x and y, so that the final drawing exactly fills the specified size. If both size values exceed the width and height of the drawing, then both coordinate values of each node are scaled up accordingly. However, if either size dimension is smaller than the corresponding dimension in the drawing, one dimension is scaled up so that the final drawing has the same aspect ratio as specified by size. Then, when rendered, the layout will be scaled down uniformly in both dimensions to fit the given size, which may cause nodes and text to shrink as well. This may not be what the user wants, but it avoids the hard problem of how to reposition the nodes in an acceptable fashion to reduce the drawing size.
If ratio = "compress" and the size attribute is set, dot attempts to compress the initial layout to fit in the given size. This achieves a tighter packing of nodes but reduces the balance and symmetry. This feature only works in dot.
If ratio = "expand", the size attribute is set, and both the width and the height of the graph are less than the value in size, node positions are scaled uniformly until at least one dimension fits size exactly. Note that this is distinct from using size as the desired size, as here the drawing is expanded before edges are generated and all node and text sizes remain unchanged.
If ratio = "auto", the page attribute is set and the graph cannot be drawn on a single page, then size is set to an ``ideal'' value. In particular, the size in a given dimension will be the smallest integral multiple of the page size in that dimension which is at least half the current size. The two dimensions are then scaled independently to the new size. This feature only works in dot.
The problem lies in the details about the ratio:
Note that this is adjusted before the size attribute constraints are
enforced. In addition, the calculations usually ignore the node sizes,
so the final drawing size may only approximate what is desired.
It seems that graphviz
lays out the nodes as points (ignoring size)
adjusts for the ratio of the point nodes (still no size for nodes)
applies the graph's size constraints (in our case, upscaling the image): here we have already reached the desired dimensions, but we're not finished...
then point nodes become nodes with a real size (by default 0.5 inch high and 0.75 inch wide)
and finally the whole output gets the margin added
The result would be bigger than A4.
Therefore if we were to make nodes and margin as small as possible, then the output should come relatively close to A4.
Setting margin to 0 and the node's shape to point as well as their width and height to the minimum values with the following graph:
digraph G{
ratio="fill";
size="8.3,11.7!";
margin=0;
node[shape=point, height=0.02, width=0.01];
foo->bar;
}
neato -Tpdf with this graph results in a PDF with dimensions 211x297mm (using 8.267 inches as width will result in a clean 210x297mm).
Unfortunately, even knowing how graphviz works in respect to ratio=fill, I don't think there's an easy way to make sure the final result is always A4 when using nodes which actually have a width and height.

Resources