tron@3636: /* $Id$ */ tron@3636: rubidium@8108: /** @file slope_func.h Functions related to slopes. */ rubidium@7764: rubidium@8108: #ifndef SLOPE_FUNC_H rubidium@8108: #define SLOPE_FUNC_H tron@3636: rubidium@8113: #include "core/math_func.hpp" rubidium@8108: #include "slope_type.h" rubidium@8108: #include "direction_type.h" rubidium@8138: #include "tile_type.h" rubidium@7678: rubidium@7678: /** rubidium@7703: * Rangecheck for Corner enumeration. rubidium@7703: * rubidium@7703: * @param corner A #Corner. rubidium@7703: * @return true iff corner is in a valid range. rubidium@7703: */ rubidium@7703: static inline bool IsValidCorner(Corner corner) rubidium@7703: { skidd13@7954: return IsInsideMM(corner, 0, CORNER_END); rubidium@7703: } rubidium@7703: rubidium@8108: rubidium@7703: /** truelight@7309: * Checks if a slope is steep. truelight@7309: * truelight@7309: * @param s The given #Slope. truelight@7309: * @return True if the slope is steep, else false. truelight@7309: */ tron@3636: static inline bool IsSteepSlope(Slope s) tron@3636: { tron@3636: return (s & SLOPE_STEEP) != 0; tron@3636: } tron@3636: truelight@7309: /** rubidium@7764: * Checks for non-continuous slope on halftile foundations. rubidium@7764: * rubidium@7764: * @param s The given #Slope. rubidium@7764: * @return True if the slope is non-continuous, else false. rubidium@7764: */ rubidium@7764: static inline bool IsHalftileSlope(Slope s) rubidium@7764: { rubidium@7764: return (s & SLOPE_HALFTILE) != 0; rubidium@7764: } rubidium@7764: rubidium@7764: /** frosch@8413: * Removes a halftile slope from a slope frosch@8413: * frosch@8413: * Non-halftile slopes remain unmodified. frosch@8413: * frosch@8413: * @param s A #Slope. frosch@8413: * @return The slope s without it's halftile slope. frosch@8413: */ frosch@8413: static inline Slope RemoveHalftileSlope(Slope s) frosch@8413: { frosch@8801: return s & ~SLOPE_HALFTILE_MASK; frosch@8413: } frosch@8413: frosch@8413: /** truelight@7309: * Return the complement of a slope. truelight@7309: * truelight@7309: * This method returns the complement of a slope. The complement of a truelight@7309: * slope is a slope with raised corner which aren't raised in the given truelight@7309: * slope. truelight@7309: * rubidium@7764: * @pre The slope must neither be steep nor a halftile slope. truelight@7309: * @param s The #Slope to get the complement. truelight@7309: * @return a complement Slope of the given slope. truelight@7309: */ tron@3636: static inline Slope ComplementSlope(Slope s) tron@3636: { rubidium@7764: assert(!IsSteepSlope(s) && !IsHalftileSlope(s)); frosch@8801: return s ^ SLOPE_ELEVATED; tron@3636: } tron@3636: rubidium@7335: /** frosch@8413: * Tests if a specific slope has exactly one corner raised. frosch@8413: * frosch@8413: * @param s The #Slope frosch@8413: * @return true iff exactly one corner is raised frosch@8413: */ frosch@8413: static inline bool IsSlopeWithOneCornerRaised(Slope s) frosch@8413: { frosch@8413: return (s == SLOPE_W) || (s == SLOPE_S) || (s == SLOPE_E) || (s == SLOPE_N); frosch@8413: } frosch@8413: frosch@8413: /** frosch@8413: * Returns the slope with a specific corner raised. frosch@8413: * frosch@8413: * @param corner The #Corner. frosch@8413: * @return The #Slope with corner "corner" raised. frosch@8413: */ frosch@8413: static inline Slope SlopeWithOneCornerRaised(Corner corner) frosch@8413: { frosch@8413: assert(IsValidCorner(corner)); frosch@8413: return (Slope)(1 << corner); frosch@8413: } frosch@8413: frosch@8413: /** rubidium@7703: * Tests if a slope has a highest corner (i.e. one corner raised or a steep slope). rubidium@7703: * rubidium@7764: * Note: A halftile slope is ignored. rubidium@7764: * rubidium@7703: * @param s The #Slope. rubidium@7703: * @return true iff the slope has a highest corner. rubidium@7703: */ rubidium@7703: static inline bool HasSlopeHighestCorner(Slope s) rubidium@7703: { frosch@8413: s = RemoveHalftileSlope(s); frosch@8413: return IsSteepSlope(s) || IsSlopeWithOneCornerRaised(s); rubidium@7703: } rubidium@7703: rubidium@7703: /** rubidium@7335: * Returns the highest corner of a slope (one corner raised or a steep slope). rubidium@7335: * rubidium@7764: * @pre The slope must be a slope with one corner raised or a steep slope. A halftile slope is ignored. rubidium@7335: * @param s The #Slope. rubidium@7678: * @return Highest corner. rubidium@7335: */ rubidium@7678: static inline Corner GetHighestSlopeCorner(Slope s) rubidium@7335: { frosch@8413: switch (RemoveHalftileSlope(s)) { rubidium@7335: case SLOPE_W: rubidium@7678: case SLOPE_STEEP_W: return CORNER_W; rubidium@7335: case SLOPE_S: rubidium@7678: case SLOPE_STEEP_S: return CORNER_S; rubidium@7335: case SLOPE_E: rubidium@7678: case SLOPE_STEEP_E: return CORNER_E; rubidium@7335: case SLOPE_N: rubidium@7678: case SLOPE_STEEP_N: return CORNER_N; rubidium@7335: default: NOT_REACHED(); rubidium@7335: } rubidium@7335: } rubidium@7335: rubidium@7582: /** rubidium@7764: * Returns the leveled halftile of a halftile slope. rubidium@7764: * rubidium@7764: * @pre The slope must be a halftile slope. rubidium@7764: * @param s The #Slope. rubidium@7764: * @return The corner of the leveled halftile. rubidium@7764: */ rubidium@7764: static inline Corner GetHalftileSlopeCorner(Slope s) rubidium@7764: { rubidium@7764: assert(IsHalftileSlope(s)); rubidium@7764: return (Corner)((s >> 6) & 3); rubidium@7764: } rubidium@7764: rubidium@7764: /** rubidium@7582: * Returns the height of the highest corner of a slope relative to TileZ (= minimal height) rubidium@7582: * rubidium@7582: * @param s The #Slope. rubidium@7582: * @return Relative height of highest corner. rubidium@7582: */ rubidium@7582: static inline uint GetSlopeMaxZ(Slope s) rubidium@7582: { rubidium@7582: if (s == SLOPE_FLAT) return 0; rubidium@7582: if (IsSteepSlope(s)) return 2 * TILE_HEIGHT; rubidium@7582: return TILE_HEIGHT; rubidium@7582: } rubidium@7582: rubidium@7678: /** rubidium@7678: * Returns the opposite corner. rubidium@7678: * rubidium@7678: * @param corner A #Corner. rubidium@7678: * @return The opposite corner to "corner". rubidium@7678: */ rubidium@7678: static inline Corner OppositeCorner(Corner corner) rubidium@7678: { rubidium@7678: return (Corner)(corner ^ 2); rubidium@7678: } rubidium@7678: rubidium@7678: /** frosch@8413: * Tests if a specific slope has exactly three corners raised. rubidium@7678: * frosch@8413: * @param s The #Slope frosch@8413: * @return true iff exactly three corners are raised rubidium@7678: */ frosch@8413: static inline bool IsSlopeWithThreeCornersRaised(Slope s) rubidium@7678: { frosch@8413: return !IsHalftileSlope(s) && !IsSteepSlope(s) && IsSlopeWithOneCornerRaised(ComplementSlope(s)); rubidium@7678: } rubidium@7678: rubidium@7678: /** rubidium@7678: * Returns the slope with all except one corner raised. rubidium@7678: * rubidium@7678: * @param corner The #Corner. rubidium@7678: * @return The #Slope with all corners but "corner" raised. rubidium@7678: */ rubidium@7678: static inline Slope SlopeWithThreeCornersRaised(Corner corner) rubidium@7678: { rubidium@7678: return ComplementSlope(SlopeWithOneCornerRaised(corner)); rubidium@7678: } rubidium@7678: rubidium@7764: /** frosch@8413: * Returns a specific steep slope frosch@8413: * frosch@8413: * @param corner A #Corner. frosch@8413: * @return The steep #Slope with "corner" as highest corner. frosch@8413: */ frosch@8413: static inline Slope SteepSlope(Corner corner) frosch@8413: { frosch@8801: return SLOPE_STEEP | SlopeWithThreeCornersRaised(OppositeCorner(corner)); frosch@8413: } frosch@8413: frosch@8413: /** frosch@8413: * Tests if a specific slope is an inclined slope. frosch@8413: * frosch@8413: * @param s The #Slope frosch@8413: * @return true iff the slope is inclined. frosch@8413: */ frosch@8413: static inline bool IsInclinedSlope(Slope s) frosch@8413: { frosch@8413: return (s == SLOPE_NW) || (s == SLOPE_SW) || (s == SLOPE_SE) || (s == SLOPE_NE); frosch@8413: } frosch@8413: frosch@8413: /** frosch@8413: * Returns the direction of an inclined slope. frosch@8413: * frosch@8413: * @param s A #Slope frosch@8413: * @return The direction the slope goes up in. Or INVALID_DIAGDIR if the slope is not an inclined slope. frosch@8413: */ frosch@8413: static inline DiagDirection GetInclinedSlopeDirection(Slope s) frosch@8413: { frosch@8413: switch (s) { frosch@8413: case SLOPE_NE: return DIAGDIR_NE; frosch@8413: case SLOPE_SE: return DIAGDIR_SE; frosch@8413: case SLOPE_SW: return DIAGDIR_SW; frosch@8413: case SLOPE_NW: return DIAGDIR_NW; frosch@8413: default: return INVALID_DIAGDIR; frosch@8413: } frosch@8413: } frosch@8413: frosch@8413: /** frosch@8413: * Returns the slope, that is inclined in a specific direction. frosch@8413: * frosch@8413: * @param dir A #DiagDirection frosch@8413: * @return The #Slope that goes up in direction dir. frosch@8413: */ frosch@8413: static inline Slope InclinedSlope(DiagDirection dir) frosch@8413: { frosch@8413: switch (dir) { frosch@8413: case DIAGDIR_NE: return SLOPE_NE; frosch@8413: case DIAGDIR_SE: return SLOPE_SE; frosch@8413: case DIAGDIR_SW: return SLOPE_SW; frosch@8413: case DIAGDIR_NW: return SLOPE_NW; frosch@8413: default: NOT_REACHED(); frosch@8413: } frosch@8413: } frosch@8413: frosch@8413: /** rubidium@7764: * Adds a halftile slope to a slope. rubidium@7764: * rubidium@7764: * @param s #Slope without a halftile slope. rubidium@7764: * @param corner The #Corner of the halftile. rubidium@7764: * @return The #Slope s with the halftile slope added. rubidium@7764: */ rubidium@7764: static inline Slope HalftileSlope(Slope s, Corner corner) rubidium@7764: { rubidium@7764: assert(IsValidCorner(corner)); rubidium@7764: return (Slope)(s | SLOPE_HALFTILE | (corner << 6)); rubidium@7764: } rubidium@7764: rubidium@7335: rubidium@7335: /** rubidium@7335: * Tests for FOUNDATION_NONE. rubidium@7335: * rubidium@7335: * @param f Maybe a #Foundation. rubidium@7335: * @return true iff f is a foundation. rubidium@7335: */ rubidium@7335: static inline bool IsFoundation(Foundation f) rubidium@7335: { rubidium@7335: return f != FOUNDATION_NONE; rubidium@7335: } rubidium@7335: rubidium@7335: /** rubidium@7335: * Tests if the foundation is a leveled foundation. rubidium@7335: * rubidium@7335: * @param f The #Foundation. rubidium@7335: * @return true iff f is a leveled foundation. rubidium@7335: */ rubidium@7335: static inline bool IsLeveledFoundation(Foundation f) rubidium@7335: { rubidium@7335: return f == FOUNDATION_LEVELED; rubidium@7335: } rubidium@7335: rubidium@7335: /** rubidium@7335: * Tests if the foundation is an inclined foundation. rubidium@7335: * rubidium@7335: * @param f The #Foundation. rubidium@7335: * @return true iff f is an inclined foundation. rubidium@7335: */ rubidium@7335: static inline bool IsInclinedFoundation(Foundation f) rubidium@7335: { rubidium@7335: return (f == FOUNDATION_INCLINED_X) || (f == FOUNDATION_INCLINED_Y); rubidium@7335: } rubidium@7335: rubidium@7335: /** rubidium@7770: * Tests if a foundation is a non-continuous foundation, i.e. halftile-foundation or FOUNDATION_STEEP_BOTH. rubidium@7770: * rubidium@7770: * @param f The #Foundation. rubidium@7770: * @return true iff f is a non-continuous foundation rubidium@7770: */ rubidium@7770: static inline bool IsNonContinuousFoundation(Foundation f) rubidium@7770: { skidd13@7954: return IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1); rubidium@7770: } rubidium@7770: rubidium@7770: /** rubidium@7770: * Returns the halftile corner of a halftile-foundation rubidium@7770: * rubidium@7770: * @pre f != FOUNDATION_STEEP_BOTH rubidium@7770: * rubidium@7770: * @param f The #Foundation. rubidium@7770: * @return The #Corner with track. rubidium@7770: */ rubidium@7770: static inline Corner GetHalftileFoundationCorner(Foundation f) rubidium@7770: { skidd13@7954: assert(IsInsideMM(f, FOUNDATION_HALFTILE_W, FOUNDATION_HALFTILE_N + 1)); rubidium@7770: return (Corner)(f - FOUNDATION_HALFTILE_W); rubidium@7770: } rubidium@7770: rubidium@7770: /** rubidium@7770: * Tests if a foundation is a special rail foundation for single horizontal/vertical track. rubidium@7770: * rubidium@7770: * @param f The #Foundation. rubidium@7770: * @return true iff f is a special rail foundation for single horizontal/vertical track. rubidium@7770: */ rubidium@7770: static inline bool IsSpecialRailFoundation(Foundation f) rubidium@7770: { skidd13@7954: return IsInsideMM(f, FOUNDATION_RAIL_W, FOUNDATION_RAIL_N + 1); rubidium@7770: } rubidium@7770: rubidium@7770: /** rubidium@7770: * Returns the track corner of a special rail foundation rubidium@7770: * rubidium@7770: * @param f The #Foundation. rubidium@7770: * @return The #Corner with track. rubidium@7770: */ rubidium@7770: static inline Corner GetRailFoundationCorner(Foundation f) rubidium@7770: { rubidium@7770: assert(IsSpecialRailFoundation(f)); rubidium@7770: return (Corner)(f - FOUNDATION_RAIL_W); rubidium@7770: } rubidium@7770: rubidium@7770: /** rubidium@7335: * Returns the foundation needed to flatten a slope. rubidium@7335: * The returned foundation is either FOUNDATION_NONE if the tile was already flat, or FOUNDATION_LEVELED. rubidium@7335: * rubidium@7335: * @param s The current #Slope. rubidium@7335: * @return The needed #Foundation. rubidium@7335: */ rubidium@7335: static inline Foundation FlatteningFoundation(Slope s) rubidium@7335: { rubidium@7335: return (s == SLOPE_FLAT ? FOUNDATION_NONE : FOUNDATION_LEVELED); rubidium@7335: } rubidium@7335: rubidium@7335: /** rubidium@7335: * Returns the along a specific axis inclined foundation. rubidium@7335: * rubidium@7335: * @param axis The #Axis. rubidium@7335: * @return The needed #Foundation. rubidium@7335: */ rubidium@7335: static inline Foundation InclinedFoundation(Axis axis) rubidium@7335: { rubidium@7335: return (axis == AXIS_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y); rubidium@7335: } rubidium@7335: rubidium@7770: /** rubidium@7770: * Returns the halftile foundation for single horizontal/vertical track. rubidium@7770: * rubidium@7770: * @param corner The #Corner with the track. rubidium@7770: * @return The wanted #Foundation. rubidium@7770: */ rubidium@7770: static inline Foundation HalftileFoundation(Corner corner) rubidium@7770: { rubidium@7770: assert(IsValidCorner(corner)); rubidium@7770: return (Foundation)(FOUNDATION_HALFTILE_W + corner); rubidium@7770: } rubidium@7770: rubidium@7770: /** rubidium@7770: * Returns the special rail foundation for single horizontal/vertical track. rubidium@7770: * rubidium@7770: * @param corner The #Corner with the track. rubidium@7770: * @return The wanted #Foundation. rubidium@7770: */ rubidium@7770: static inline Foundation SpecialRailFoundation(Corner corner) rubidium@7770: { rubidium@7770: assert(IsValidCorner(corner)); rubidium@7770: return (Foundation)(FOUNDATION_RAIL_W + corner); rubidium@7770: } rubidium@7770: rubidium@8108: #endif /* SLOPE_FUNC_H */