// Animesh Fatehpuria #include "bits/stdc++.h" using namespace std; const int N = 55; const int OFFSET = 51; int t, n, m; int triVal[N][N][N]; int linVal[N][N]; long long dp[N][N][N + N]; struct point { long long x, y; }; point arr[N], imp[N]; point head; int color[N]; deque < int > order; inline long long area(point a, point b, point c) { return (a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y)); } inline bool insideTriangle(int i, int j, int k, int l) { long long p = area(arr[i], arr[j], arr[k]); long long q = area(arr[i], arr[j], imp[l]); long long r = area(arr[i], arr[k], imp[l]); long long s = area(arr[j], arr[k], imp[l]); return (abs(p) == abs(q) + abs(r) + abs(s)); } inline bool onSegment(int i, int j, int k) { int xL = min(arr[i].x, arr[j].x); int xR = max(arr[i].x, arr[j].x); int yL = min(arr[i].y, arr[j].y); int yR = max(arr[i].y, arr[j].y); int x = imp[k].x , y = imp[k].y; return (x >= xL && x <= xR && y >= yL && y <= yR && (area(arr[i], arr[j], imp[k]) == 0)); } inline long long dist(point a, point b){ return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } inline bool is_right(point a, point b){ long long dx = (b.x - a.x); long long dy = (b.y - a.y); return (dx > 0) || (dx == 0 && dy > 0); } inline bool compare(int i, int j){ point b = arr[i], c = arr[j]; long long det = area(head, b, c); if(det == 0){ if(is_right(head, b) != is_right(head, c)) return is_right(head, b); return (dist(head, b) < dist(head, c)); } return (det > 0); } inline void preprocess() { memset(triVal, 0, sizeof triVal); memset(linVal, 0, sizeof linVal); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (i == j) { continue; } for (int k = 1; k <= n; k++) { if (i == k || j == k) { continue; } for (int l = 1; l <= m; l++) { if (insideTriangle(i, j, k, l)) { triVal[i][j][k] += color[l]; } } } for (int l = 1; l <= m; l++) { if (onSegment(i, j, l)) { linVal[i][j] += color[l]; } } } } } inline long long solve(int pos, int last, int sum) { if (dp[pos][last][sum + OFFSET] != -1) { return dp[pos][last][sum + OFFSET]; } if (pos == (int) order.size()) { return (sum == 0); } long long res = solve(pos + 1, last, sum); if (last == 0) { int newSum = sum + linVal[order[0]][order[pos]]; res += solve(pos + 1, pos, newSum); } else { int newSum = sum - linVal[order[0]][order[last]]; newSum += triVal[order[0]][order[last]][order[pos]]; res += solve(pos + 1, pos, newSum); } return dp[pos][last][sum + OFFSET] = res; } inline long long badPolygons() { long long bad = n; for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { if (linVal[i][j] == 0) { bad++; } } } return bad; } int main() { cin >> t; while (t--) { cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> arr[i].x >> arr[i].y; } for (int i = 1; i <= m; i++) { cin >> imp[i].x >> imp[i].y; cin >> color[i]; if (color[i] == 0) { color[i] = -1; } } preprocess(); long long res = 0; for (int i = 1; i <= n; i++) { order.clear(); for (int j = 1; j <= n; j++) { if (arr[j].y > arr[i].y) { order.push_back(j); } else if ((arr[j].y == arr[i].y) && (arr[j].x > arr[i].x)) { order.push_back(j); } } head = arr[i]; sort(order.begin(), order.end(), compare); order.push_front(i); memset(dp, -1, sizeof dp); res += solve(1, 0, 0); } cout << (res - badPolygons()) << '\n'; } }