/** * @name pick_close_point * * Choose the edge point that is closest to the critical point. This * point may not be exactly vertical from the critical point. */ EDGEPT *Wordrec::pick_close_point(EDGEPT *critical_point, EDGEPT *vertical_point, int *best_dist) { EDGEPT *best_point = nullptr; int this_distance; int found_better; do { found_better = false; this_distance = edgept_dist (critical_point, vertical_point); if (this_distance <= *best_dist) { if (!(same_point (critical_point->pos, vertical_point->pos) || same_point (critical_point->pos, vertical_point->next->pos) || (best_point && same_point (best_point->pos, vertical_point->pos)) || is_exterior_point (critical_point, vertical_point))) { *best_dist = this_distance; best_point = vertical_point; if (chop_vertical_creep) found_better = true; } } vertical_point = vertical_point->next; } while (found_better == true); return (best_point); }
/** * @name vertical_projection_point * * For one point on the outline, find the corresponding point on the * other side of the outline that is a likely projection for a split * point. This is done by iterating through the edge points until the * X value of the point being looked at is greater than the X value of * the split point. Ensure that the point being returned is not right * next to the split point. Return the edge point in *best_point as * a result, and any points that were newly created are also saved on * the new_points list. */ void Wordrec::vertical_projection_point(EDGEPT *split_point, EDGEPT *target_point, EDGEPT** best_point, EDGEPT_CLIST *new_points) { EDGEPT *p; /* Iterator */ EDGEPT *this_edgept; /* Iterator */ EDGEPT_C_IT new_point_it(new_points); int x = split_point->pos.x; /* X value of vertical */ int best_dist = LARGE_DISTANCE;/* Best point found */ if (*best_point != nullptr) best_dist = edgept_dist(split_point, *best_point); p = target_point; /* Look at each edge point */ do { if (((p->pos.x <= x && x <= p->next->pos.x) || (p->next->pos.x <= x && x <= p->pos.x)) && !same_point(split_point->pos, p->pos) && !same_point(split_point->pos, p->next->pos) && !p->IsChopPt() && (*best_point == nullptr || !same_point((*best_point)->pos, p->pos))) { if (near_point(split_point, p, p->next, &this_edgept)) { new_point_it.add_before_then_move(this_edgept); } if (*best_point == nullptr) best_dist = edgept_dist (split_point, this_edgept); this_edgept = pick_close_point(split_point, this_edgept, &best_dist); if (this_edgept) *best_point = this_edgept; } p = p->next; } while (p != target_point); }
/********************************************************************** * near_point * * Find the point on a line segment that is closest to a point not on * the line segment. Return that point in near_pt. Returns whether * near_pt was newly created. **********************************************************************/ bool Wordrec::near_point(EDGEPT *point, EDGEPT *line_pt_0, EDGEPT *line_pt_1, EDGEPT **near_pt) { TPOINT p; float slope; float intercept; float x0 = line_pt_0->pos.x; float x1 = line_pt_1->pos.x; float y0 = line_pt_0->pos.y; float y1 = line_pt_1->pos.y; if (x0 == x1) { /* Handle vertical line */ p.x = (inT16) x0; p.y = point->pos.y; } else { /* Slope and intercept */ slope = (y0 - y1) / (x0 - x1); intercept = y1 - x1 * slope; /* Find perpendicular */ p.x = (inT16) ((point->pos.x + (point->pos.y - intercept) * slope) / (slope * slope + 1)); p.y = (inT16) (slope * p.x + intercept); } if (is_on_line (p, line_pt_0->pos, line_pt_1->pos) && (!same_point (p, line_pt_0->pos)) && (!same_point (p, line_pt_1->pos))) { /* Intersection on line */ *near_pt = make_edgept(p.x, p.y, line_pt_1, line_pt_0); return true; } else { /* Intersection not on line */ *near_pt = closest(point, line_pt_0, line_pt_1); return false; } }
bool is_valid_rect() { int i, k; bool marked[4]; for(i=0;i<4;i++) { if(lines[i].length_square == 0) { printf("length_square == 0\n"); return false; } marked[i] = false; } rect.p[0].x = lines->p[0].x; rect.p[0].y = lines->p[0].y; rect.p[1].x = lines->p[1].x; rect.p[1].y = lines->p[1].y; marked[0] = true; bool found; for(i=2;i<4;i++) { found = false; for(k=0;k<4;k++) { if(!marked[k]) { if(same_point(lines[k].p, rect.p+i-1)) { found = true; rect.p[i].x = lines[k].p[1].x; rect.p[i].y = lines[k].p[1].y; marked[k] = true; break; } else if(same_point(lines[k].p+1, rect.p+i-1)) { found = true; rect.p[i].x = lines[k].p[0].x; rect.p[i].y = lines[k].p[0].y; marked[k] = true; break; } } } if(!found) { return false; } } for(i=0;i<4;i++) if(!marked[i]) { if(same_point(lines[i].p, rect.p)) { if(!(same_point(lines[i].p+1, rect.p+3))) return false; } else if(same_point(lines[i].p+1, rect.p)) { if(!(same_point(lines[i].p, rect.p+3))) return false; } else return false; break; } for(i=0;i<4;i++) { Point *a = i == 0 ? rect.p+3 : rect.p+i-1; Point *o = rect.p+i; Point *b = i == 4 ? rect.p : rect.p+i+1; if(!perpendicular(a, o, b)) return false; } return true; }
/* * We simplify the pattern recursively, using node "start" as a * "zipper" to zip the pattern up ("start" moves from left to * right as the recursion proceeds, and the recusion ends when * "start" reaches the end of the pattern). * * Overall strategy: We "check" whether we can remove "start" without * changing what ordinal the pointed pattern notates. But if we remove * "start", we have to remove anything connected to it (via less1, * or via decompositions), so we have to ask the same question about * all those nodes as well, which in turn requires asking the same * question about any node THEY'RE connected to, and so on. */ static pattern *simplify_recurse( pattern *p, node *start ) { node *n; pattern *q; /* * Mark all nodes in the pattern as being unchecked during this iteration */ for ( n = p->first_node; n; n = n->next ) n->simplify_data = SIMPL_UNCHECKED; /* * Under no circumstances would we remove the pattern's designated point */ if ( start == p->point ) { start = start->next; if ( !start ) return p; } /* * Attempt to mark "start" for removal. * If the attempt fails (because it would * require removing p->point) then move on * to the next start. */ if ( ! mark_for_removal(p,start,start) ) { if ( !start->next ) return p; return simplify_recurse( p, start->next ); } /* * If "start" was successfully marked for * removal, then remove it, along with anything * else that was marked as collateral damage. * Actually, do all this in a copy q of p. */ q = execute_removal(p); /* * Check whether the copy q, with "start" removed, * still notates the same ordinal that p does. * If so, continue trying to further simplify q. * If not, revert back to p and increment "start". */ if ( same_point(q,p) ) { start = isom(start,q); if ( start ) return simplify_recurse( q, start ); else return q; } else { if ( start->next ) return simplify_recurse( p, start->next ); else return p; } }
/* Move pt to a random, valid position within the * but it won't be on the map borders. */ inline Point random_point_within_rect(Rect r) { return (Point) { .x = r.x + (rand() % (r.w - 1)) + 1, .y = r.y + (rand() % (r.h - 1)) + 1 }; } /* Move given point one unit in the given direction. */ inline void move_point(Point p[static 1], int direction) { switch (direction) { case KEY_UP: p->y -= 1; break; case KEY_LEFT: p->x -= 1; break; case KEY_DOWN: p->y += 1; break; case KEY_RIGHT: p->x += 1; break; } } /*** Snake utilities ***/ /* Is this point the snake? */ inline bool point_is_snake(Point p, Snake s[static 1]) { for (size_t i = 0; i < s->length; ++i) if (same_point(p, s->history[i])) return true; return false; } /* Identical to above, but does not include the head. */ inline bool point_is_tail(Point p, Snake s[static 1]) { for (size_t i = 1; i < s->length; ++i) if (same_point(p, s->history[i])) return true; return false; } /* Move all the snake's tail pieces up one place, then move its head one unit in * the given direction. */ void move_snake(Snake s[static 1], int direction) { for (size_t i = s->length; i > 0; --i) s->history[i] = s->history[i-1]; move_point(&s->history[0], direction); } /* Will pathing to this point lose the game? */ inline bool point_is_unpathable(Point p, Rect r, Snake s[static 1]) { return (!point_is_within_rect(p, r) || point_is_tail(p, s)); } /*** Directions ***/ /* Is this integer a valid direction? */ inline bool input_is_direction(int input) { switch (input) { case KEY_LEFT: case KEY_UP: case KEY_RIGHT: case KEY_DOWN: return true; default: return false; } } /* Return the opposite direction of input */ inline int opposite_direction(int direction) { int opp = ERR; switch (direction) { case KEY_LEFT: opp = KEY_RIGHT; break; case KEY_UP: opp = KEY_DOWN; break; case KEY_RIGHT: opp = KEY_LEFT; break; case KEY_DOWN: opp = KEY_UP; break; } return opp; }