siemens-rtl/try_sweep.c
2023-07-11 14:40:13 +02:00

343 lines
12 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef lint
static char sccs_id[] = "@(#)try_sweep.c 5.3 9/1/88";
#endif
/*
* Copyright 1988 by Siemens Research and Technology Laboratories, Princeton, NJ
*
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of Siemens Research and Technology
* Laboratories not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
*
*
* SIEMENS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
* SIEMENS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include "copyright.h"
#include <stdio.h>
/****************************************************************************
try_edge_sweep.c: by Michael Berman
RTL Windows System
last modified: March 27, 1987
version: 0.4
****************************************************************************/
#include "tileD.h"
#include "tile.h"
#include "twin.h"
#define SPLIT_RECT(r) r.left_x,r.top_y,r.right_x,r.bottom_y
/****************************************************************************
EDGE SWEEPING
Problem: Given a line segment which is parallel with one of the
sides of the desktop, and which is contained within one or
more tiles, 'sweep' it perpendicularly until it touches a new
tile or the desktop edge. The value returned represents the
pixel position, on the desktop, of the furthest extent of the
sweep. (Note that this is NOT the same as the distance the
edge moved; you can derive that by subtracting/adding the
extent from/to the original edge position.)
Due to the asymmetry of corner stitching, there are two quite
different versions of this, namely horizontal (which sweeps a
vertical segment either to the Left or R) and vertical (sweeps
a horizontal segment up or Down).
This will be implemented as two boolean funtions, returning
TRUE if the sweep was successful, and FALSE if there is a
logical inconsistency in the arguments. The "extent" argument
will be a pointer to a location to give the answer, which is
the x (in the case of horizontal) or y (in the case of
vertical) marking the extent of the sweep.
The external entry point for edge sweeping is: Trial_Edge_Sweep
****************************************************************************/
/* variables with scope over all functions in this file */
Basetype current_extent; /* best current guess at extent */
Side global_dir; /* direction of sweep, used by enumeration fcn */
bool touched_solid_tile; /* flag set if the enumeration fcn finds solid */
#define ASSERT(a,m) \
{ \
if (!(a)) \
printf("YOW! %s \n",m);\
}
void Enum_Horiz_Extent();
bool Vert_Sweep(), Horiz_Sweep();
bool
Trial_Edge_Sweep(p1,p2,dir,extent)
TWPoint p1, p2;
Side dir;
Basetype *extent;
{
if ((dir == Top) || (dir == Bottom))
return(Vert_Sweep(p1,p2,dir,extent));
else if ((dir == Left) || (dir == Right))
return(Horiz_Sweep(p1,p2,dir,extent));
else
return(FALSE);
}
bool
Horiz_Sweep(p1, p2, dir, extent)
TWPoint p1, p2;
Side dir;
Basetype *extent;
/****************************************************************************
Arguments:
p1, p2: The points defining the line segment. Since this is a
horizontal sweep, p1.x must equal p2.x. p1 must be above p2;
hence p1.y <= p2.y.
dir: The direction to sweep-- must be Left or Right.
extent: Pointer to Basetype in which result is returned.
Returns: Boolean flag indicating success/failure of sweep.
Modifies: *extent (parameter)
Description: Horiz_Sweep performs a horizontal line sweep, that is,
it simulates moving a vertical line segment in the horizontal
direction indicated by "dir" (= Left or Right) as far as it will go
until it first touches a solid tile. The assumption made is
that the line segment you start from is at the edge of a solid
tile; therefore, it is moved one pixel in the appropriate
direction before the sweep begins. If after moving it is
still on a solid tile, the original position is returned. The
value of the Boolean function indicates whether the sweep was
performed; a return of "false" indicates that the arguments
were incorrect or contradictory. The pixel location of the
furthest position of the sweep is returned in the Basetype
pointed to by "extent". Because all left tile edges are even
and right edges odd, a left-hand sweep always returns an even
number, while a right-hand sweep returns an odd number.
Logic: First, the arguments are checked for consistency; if an error
is found, return(FALSE). Before the call, the value of
current_extent is initialized to point to the appropriate
desktop edge (left for a left sweep, right for a right sweep.)
current_extent is used to store the position of the "closest"
edge found so far. Because the horizontal space tiles are
required to be maximal, we simply examine each tile that the
line segment crosses and find the tile that ends "closest" to
the line segment, which is equivalent to the maximum extent of
a sweep before touching a new tile. Tiles_In_Area is used to
enumerate the set of tiles crossed by the line segment, which
actually is passed as a rectangle of width 2. The
call to Tiles_In_Area uses the enumeration function
Enum_Horiz_Tiles which is defined above; the result is stored
in current_extent. The enumeration also checks for solid tiles;
if found, then a flag "touched_solid_tile" is set, so that the
unchanged edge can be returned.
****************************************************************************/
{
TWRectangle Desktop_View, r;
if (p1.x != p2.x)
return(FALSE);
r.top_y = p1.y;
r.bottom_y = p2.y;
if (r.top_y > r.bottom_y)
return(FALSE);
Desktop_View = Tilwin_Get_Desktop_Rectangle();
switch(dir)
{
case Left:
if (!Is_Even_Number(p1.x))
return(FALSE);
else
{
current_extent = Desktop_View.left_x;
r.left_x = p1.x - 2;
r.right_x = r.left_x + 1;
}
break;
case Right:
if (Is_Even_Number(p1.x))
return(FALSE);
else
{
current_extent = Desktop_View.right_x;
r.right_x = p1.x + 2;
r.left_x = r.right_x - 1;
}
break;
default:
return(FALSE);
}
global_dir = dir;
touched_solid_tile = FALSE;
Tiles_In_Area(SPLIT_RECT(r), Enum_Horiz_Extent);
*extent = (touched_solid_tile)? p1.x : current_extent;
ASSERT((Is_Even_Number(current_extent) && dir == Left) ||
(!(Is_Even_Number(current_extent)) && dir == Right),
"Parity error in current_extent -- Horiz_Sweep");
return(TRUE);
}
bool
Vert_Sweep(p1, p2, dir, extent)
TWPoint p1, p2;
Side dir;
Basetype *extent;
/****************************************************************************
Arguments:
p1, p2: The points defining the line segment. Since this is a
vertical sweep, p1.y must equal p2.y. p1 must be to the left
of p2; hence, p1.x <= p2.x;
dir: The direction to sweep-- must be Top or Bottom.
extent: pointer to Basetype in which result is returned.
Returns: Boolean flag indicating success/failure of sweep.
Modifies: *extent (parameter)
Description: Vert_Sweep performs a vertical line sweep, that is, it
simulates moving a horizontal line segment in the vertical
direction indicated by "dir" (= Top or Bottom) as far as it will
go until it first touches a solid tile. The assumption made is
that the line segment you start from is at the edge of a solid
tile; therefore it is moved one pixel in the appropriate direction
before the sweep begins. If, after moving it is still on a solid
tile, the original position is returned. The values for the
function and the return value *extent are the same as for
Horiz_Sweep. Because all top tile edges are even and bottom
edges odd, a sweep Up will always return an even number, while
a sweep down returns an odd number.
Logic: A little more complicated than the horizontal case due to the
asymetry of corner stitching. After checking for consistency,
we find the initial line segment, which is one pixel above or
below the line segment passed (depending on the direction of
the sweep. We find the tile(s) which
contain the initial line segment. If the initial line is not
entirely within a single space tile, then the original edge is
returned without change. If the segment is contained
entirely within a single space tile, then we move to the edge
of the tile, and advance the line segment just one pixel
further, beyond the original space tile. This process is
iterated until at least part of the line segment is not in a
space tile. (Note that if the two points of the segment are
in different space tiles, there MUST be a solid tile somewhere
in between.) This process may lead to the segment crossing
solid tiles, or to the edge of the desktop. Once this is
done, the y value is "backed up" by 1.
****************************************************************************/
{
Tile *tpl, *tpr;
TWRectangle r;
Basetype y_extent;
if (p1.y != p2.y)
return(FALSE);
r.left_x = p1.x;
r.right_x = p2.x;
if (r.left_x > r.right_x)
return(FALSE);
if (dir == Top)
{
if (!Is_Even_Number(p1.y))
return(FALSE);
}
else if (dir == Bottom)
{
if (Is_Even_Number(p1.y))
return(FALSE);
}
else
return(FALSE);
y_extent = (dir == Top)? p1.y - 1: p1.y + 1;
tpl = (Tile *)Tile_at_Point(p1.x,y_extent);
tpr = (Tile *)Tile_at_Point(p2.x,y_extent);
while ((tpl == tpr) &&
(tpl != NULL_TILE) &&
(Tile_Get_Type(tpl) == Space))
{
y_extent = (dir == Top)? Tile_Get_Corners(tpl).top_y - 1:
Tile_Get_Corners(tpl).bottom_y + 1;
tpl = (Tile *)Tile_at_Point(p1.x,y_extent);
tpr = (Tile *)Tile_at_Point(p2.x,y_extent);
}
y_extent = (dir == Top)? y_extent + 1 : y_extent - 1;
ASSERT((Is_Even_Number(y_extent) && dir == Top) ||
(!(Is_Even_Number(y_extent)) && dir == Bottom),
"Parity error in y_extent -- Vert_Sweep");
*extent = y_extent;
return(TRUE);
}
void
Enum_Horiz_Extent(tp)
Tile *tp;
/****************************************************************************
Arguments:
tp: Pointer to tile to be examined.
Modifies:
current_extent (as a side effect)
touched_solid_tile (as a side effect)
Description: Enum_Horiz_Extent is used by Horiz_Sweep only. It
looks at a tile and checks whether the left (or right,
depending on sweep direction) edge of the tile is more
constraining than the previous best, which is current_extent.
We also set a flag if we hit a solid tile -- once this is
set TRUE, any additional enums do nothing.
This function is passed as a parameter to Tiles_In_Area, and
executed once for each tile (tp) in the specified range.
Logic: The operation of the function is controlled by the variable
current_extent, which is global to this file. Each time
Enum_Horiz_Extent is called (for a particular tile) it checks
whether that tile represents a greater "extent" than the
previous best. That is, is this tile further to the left (or
right) than the previous best. The choice of left or
right is determined by the value of global_dir, which is
of scope external to Enum_Horiz_Extent.
****************************************************************************/
{
if (!touched_solid_tile) /* otherwise, don't bother */
if (Tile_Get_Type(tp) == Space)
{
if (global_dir == Left)
{
if (Left_X(tp) > current_extent)
{
current_extent = Left_X(tp);
}
}
else /* global_dir == Right */
{
if (Right_X(tp) < current_extent)
{
current_extent = Right_X(tp);
}
}
}
else
touched_solid_tile = TRUE;
}