Instructions to use XXXpilar/Fastfill-test with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use XXXpilar/Fastfill-test with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download code/fastfill/anchors.py from XXXpilar/Fastfill-test: direct link, hf CLI and curl.
- Browser
- Download file 17.7 kB
-
https://huggingface.co/XXXpilar/Fastfill-test/resolve/main/code/fastfill/anchors.py
- Command line
-
hf download hf://XXXpilar/Fastfill-test/code/fastfill/anchors.py
-
curl -L -o anchors.py https://huggingface.co/XXXpilar/Fastfill-test/resolve/main/code/fastfill/anchors.py
17.7 kB
| """Object scope for training: drop structure, infer support anchors, keep a support-closed subset. | |
| anchor = "floor" | "object" | "wall" | "ceiling" | "fixed". Adapters set anchor/parent from source evidence when the | |
| source has it (placement flags, explicit parent ids); otherwise `infer_anchors` derives them from boxes: | |
| ceiling hanging categories (pendant, chandelier, ...) whatever their z or source anchor (one at z=0 is | |
| misplaced), or top within 10 cm of the room height above 1 m | |
| floor bottom at most FLOOR_Z = 10 cm above z=0 (sunk boxes too, so build.prep can drop and count them), or | |
| floor furniture (bed, table, sofa, ...) at most FURNITURE_FLOOR_Z = 50 cm up with nothing under it | |
| (annotation z-noise, boxes that start above the legs; build.prep snaps them to the floor) | |
| object bottom within 5 cm of the top of a floor/object box whose footprint contains its center; | |
| seats, beds and rugs are never parents (bbox top = backrest / headboard; a rug is not a surface) | |
| wall wall art (painting, mirror, ...) with no support below, or anything else elevated without one | |
| fixed floor furniture that can hang (cabinet, shelf, vanity...) floating <= 50 cm with nothing below in a | |
| designer (polygon) room: a wall-hung unit, out of scope to place, shown to the model as a fixed box | |
| Box-level contact is weak evidence of support; build.py counts evidence and inferred supports separately. | |
| `fixed_geometry` picks the structure boxes the model is told about (never placed): doors, windows, columns, stairs, | |
| fireplaces, radiators, partitions, low beams... below FIXED_MAX_Z; surface finishes, sockets/drains, curtains and | |
| slabs covering most of the room are left out, and a "wall" box only counts when it stands inside the room. | |
| """ | |
| import math | |
| import re | |
| from shapely.geometry import Point, Polygon | |
| from fastfill.scene import footprint, head, norm_cat | |
| FLOOR_Z = 0.10 # bottoms up to 10 cm above the floor count as standing on it (build.prep snaps them to z=0) | |
| # Strong architectural words mark structure anywhere in the name; floor/wall/ceiling/column are usually modifiers | |
| # (plant_floor, floor lamp, wall_shelving_unit, locker_column) and mark structure only in purely architectural | |
| # names ("wall", "Wall design", "floor mold"). | |
| STRUCTURE = re.compile(r"\b(door|window|curtain|drape|blind|beam|pillar|stair|staircase|stairway|stairwell|railing|rail|" | |
| r"handrail|banister|guardrail|balustrade|baseboard|radiator|opening|doorframe|partition|fireplace|" | |
| r"chimney|otherstructure|structure|doorway|arch|archway|bulkhead|niche|fence|step|ramp|elevator|duct|" | |
| r"drain|pipe|socket|outlet|tile)s?\b") | |
| # furniture whose name borrows a structure word: fireplace_console, pillar_candle, clothes rail, portable_partition_panel | |
| NOT_STRUCTURE = re.compile(r"\b(lamp|light|fan|cabinet|shelf|mat|rug|towel|chair|table|console|stool|candle|figurine|box|" | |
| r"plant|planter|basket|display|station|clothes|freestanding|portable|ladder|bench|sofa|couch|" | |
| r"bed|wardrobe|desk|seat|bookcase|bookshelf|dresser|sideboard|ottoman)s?\b") | |
| SURFACE = r"(wall|floor|ceiling|column)s?" | |
| ARCH = (r"(panel|paneling|design|combination|mold|molding|moulding|background|trim|skirting|board|tile|cladding|covering|" | |
| r"decoration|sticker|styling|decorative|decor|structural|support|concrete|low|half|suspended)s?") | |
| HANGING = re.compile(r"\b(pendant|chandelier|ceiling|downlight|hanging)s?\b") | |
| NOT_HANGING = re.compile(r"\b(chair|stool|seat|swing)\b") # a hanging chair stands on its own frame | |
| # soft covers draped over a bed or sofa (their boxes cover the bed): not objects to place, not floor obstacles | |
| SOFT_COVERS = {"bedding", "comforter", "blanket", "quilt", "duvet", "bedspread", "bedcover", "coverlet"} | |
| # floor furniture whose box bottom sits up to FURNITURE_FLOOR_Z high with nothing under it stands on the floor | |
| # (annotation z-noise, boxes that start above the legs); without this it fell through to 'wall' and vanished | |
| FLOOR_FURNITURE = {"bed", "sofa", "couch", "loveseat", "sectional", "table", "desk", "chair", "armchair", "stool", "bench", | |
| "ottoman", "cabinet", "wardrobe", "dresser", "bookcase", "bookshelf", "sideboard", "nightstand", | |
| "fridge", "refrigerator", "oven", "stove", "dishwasher", "washer", "dryer", "piano", "tub", | |
| "bathtub", "toilet", "console", "stand", "chest", "armoire", "shelf", "cupboard"} | |
| FURNITURE_FLOOR_Z = 0.50 # floating up to here with nothing below: a floor piece (snapped to z=0 by build.prep) | |
| FURNITURE_SUNK_Z = 0.30 # any floor box sunk up to here: same (deeper boxes belong to a lower storey) | |
| # furniture that cannot hang on a wall: floating with nothing below it is on the floor with a noisy z anywhere | |
| GROUND_ONLY = {"bed", "sofa", "couch", "loveseat", "sectional", "chair", "armchair", "table", "desk", "fridge", | |
| "refrigerator", "oven", "stove", "dishwasher", "stool", "bench", "ottoman", "piano", "tub", "bathtub", | |
| "washer", "dryer", "wardrobe", "armoire", "bookcase", "dresser"} | |
| SOFT_HANGINGS = {"curtain", "curtains", "drape", "drapes", "blind", "blinds", "shade", "shades", "screening", "valance"} | |
| # structure that has no footprint of its own: finishes, fixtures, the room's own slabs | |
| FINISH = {"floor", "ceiling", "tile", "tiles", "baseboard", "skirting", "trim", "mold", "molding", "moulding", "panel", | |
| "paneling", "board", "boards", "cladding", "covering", "socket", "outlet", "drain", "pipe", "pipes", "design", | |
| "decoration", "sticker", "background", "wallpaper"} | |
| FIXED_MAX_Z = 1.5 # structure whose bottom is higher does not shape the floor layout (ceiling beams, ducts) | |
| DIVIDERS = {"partition", "divider", "screen"} # a "partition panel" is an obstacle, not a wall finish | |
| # scans: box z is noisy, so floating floor furniture is on the floor (not a wall-hung unit), whatever the boundary type | |
| SCANNED = {"Scan2CAD", "MultiScan", "InternScenes_arkit", "InternScenes_scannet", "InternScenes_mp3d", | |
| "InternScenes_3rscan"} | |
| def hanging(category): | |
| nc = norm_cat(category) | |
| return bool(HANGING.search(nc)) and not NOT_HANGING.search(nc) | |
| WALL_ART = re.compile(r"\b(painting|picture|poster|artwork|art|mirror|whiteboard|blackboard|frame)s?\b") | |
| FLAT = {"rug", "carpet", "mat", "doormat", "bathmat", "placemat", "playmat", "floormat", "yogamat", "exercisemat", | |
| "fitnessmat"} | |
| FLAT |= {w + "s" for w in FLAT} | |
| NO_TOP = {"sofa", "couch", "loveseat", "sectional", "bed", "armchair", "chair", "bench"} | FLAT # not a support surface | |
| def is_structure(category): | |
| c = re.sub(r"[^a-z]+", " ", (category or "").lower()) | |
| if NOT_STRUCTURE.search(c): | |
| return False | |
| return bool(STRUCTURE.search(c)) or (bool(re.search(rf"\b{SURFACE}\b", c)) | |
| and not re.sub(rf"\b({SURFACE}|{ARCH})\b", " ", c).strip()) | |
| def infer_anchors(room, tol=0.05): | |
| objs = room["objects"] | |
| fps = {o["id"]: Polygon(footprint(o)) for o in objs} | |
| height = room.get("height") | |
| hull = room.get("boundary_type") == "hull" or room.get("source") in SCANNED | |
| for o in sorted(objs, key=lambda o: o["pos"][2]): | |
| if hanging(o["category"]): # before the floor rule and any source anchor: a chandelier at z=0 is misplaced | |
| o["anchor"] = "ceiling" | |
| continue | |
| if o.get("anchor"): | |
| continue | |
| z, nc = o["pos"][2], norm_cat(o["category"]) | |
| if z <= FLOOR_Z: # one-sided: sunk boxes stay floor so build.prep drops and counts them | |
| o["anchor"] = "floor" | |
| continue | |
| c = Point(o["pos"][0], o["pos"][1]) | |
| below = [p for p in objs if p is not o and p.get("anchor") in ("floor", "object") and head(p) not in NO_TOP | |
| and abs(p["pos"][2] + p["size"][2] - z) < tol and fps[p["id"]].contains(c)] | |
| if below: # a frame standing on a dresser is on it; art above a sofa is not (NO_TOP) | |
| o["anchor"], o["parent"] = "object", max(below, key=lambda p: p["pos"][2] + p["size"][2])["id"] | |
| o["anchor_inferred"] = True | |
| elif WALL_ART.search(nc): | |
| o["anchor"] = "wall" | |
| elif z <= FURNITURE_FLOOR_Z and head(o) in FLOOR_FURNITURE: | |
| # nothing under it: on the floor with a noisy z (scans; anything that cannot hang), or a wall-hung | |
| # unit in a designer room (vanity, floating TV console): shown as fixed, not placed | |
| o["anchor"] = "floor" if hull or head(o) in GROUND_ONLY else "fixed" | |
| elif height and z + o["size"][2] > height - 2 * tol and z > 1.0: | |
| o["anchor"] = "ceiling" | |
| else: | |
| o["anchor"] = "wall" | |
| return room | |
| def fixed_geometry(room, band=0.10, intrusion=0.05): | |
| """Structure boxes to show the model as immovable (see module doc). Returns copies with tilted/anchor cleared. | |
| Which of them survive next to the reference layout (covered, outside, slabs) is build.prep's decision.""" | |
| out = [] | |
| shell = Polygon(room["boundary"]).buffer(0) if room.get("boundary") else None | |
| inner = shell.buffer(-band) if shell is not None else None | |
| hull = room.get("boundary_type") == "hull" | |
| for o in room["objects"]: | |
| if not structural(o): | |
| continue | |
| words, h = set(norm_cat(o["category"]).split()), head(o) | |
| finish = (h in FINISH or h.rstrip("s") in FINISH) and not words & DIVIDERS | |
| if finish or words & SOFT_HANGINGS or o["pos"][2] >= FIXED_MAX_Z: | |
| continue | |
| fp = Polygon(footprint(o)) | |
| if shell is not None and fp.area >= 0.8 * shell.area: # a slab under another name | |
| continue | |
| # a "wall" box is the room's own wall unless it stands inside a polygon room (a partition); in a hull room | |
| # the walls stand inside the hull by construction, so none of them is a partition | |
| if h == "wall" and (hull or inner is None or fp.intersection(inner).area < intrusion): | |
| continue | |
| out.append({k: v for k, v in o.items() if k not in ("anchor", "parent", "tilted", "anchor_inferred")}) | |
| return out | |
| def structural(o): | |
| """Source-flagged architecture, or a structure name on something that does not stand on another object (a | |
| power 'outlet' strip or a lever 'arch' file on a desk is an object, not architecture).""" | |
| return bool(o.get("structure")) or (is_structure(o["category"]) and not o.get("parent")) | |
| def annotate(room): | |
| """Structure and soft covers removed, anchors inferred: every remaining box with anchor/parent set.""" | |
| objs = [dict(o) for o in room["objects"] if not (structural(o) or head(o) in SOFT_COVERS)] | |
| return infer_anchors({**room, "objects": objs})["objects"] | |
| def closed(objs, keep=("floor", "object")): | |
| """Objects whose anchor is in `keep` and whose support chain is entirely kept, in input order.""" | |
| kept, ids = [], set() | |
| for o in sorted(objs, key=lambda o: o["pos"][2]): # parents sit lower than children | |
| if o["anchor"] in keep and (o.get("parent") is None or o["parent"] in ids): | |
| kept.append(o) | |
| ids.add(o["id"]) | |
| order = {o["id"]: k for k, o in enumerate(objs)} | |
| return sorted(kept, key=lambda o: order[o["id"]]) | |
| def scope_objects(room, keep=("floor", "object")): | |
| """Structure removed, anchors inferred, objects outside `keep` dropped together with their dependants.""" | |
| return {**room, "objects": closed(annotate(room), keep)} | |
| if __name__ == "__main__": | |
| room = {"height": 2.6, "objects": [ | |
| {"id": "desk", "category": "desk", "size": [1.2, .6, .75], "pos": [1, 1, 0], "yaw": 0}, | |
| {"id": "lamp", "category": "table lamp", "size": [.2, .2, .4], "pos": [1.2, 1, .75], "yaw": 0}, | |
| {"id": "pic", "category": "painting", "size": [.8, .05, .6], "pos": [1, 0, 1.4], "yaw": 0}, | |
| {"id": "cl", "category": "pendant lamp", "size": [.5, .5, .3], "pos": [2, 2, 2.0], "yaw": 0}, | |
| {"id": "sofa", "category": "sofa", "size": [2, .9, .8], "pos": [3, 3, 0], "yaw": 0}, | |
| {"id": "art", "category": "picture frame", "size": [.6, .05, .5], "pos": [3, 3, .8], "yaw": 0}, | |
| {"id": "vase", "category": "vase", "size": [.1, .1, .2], "pos": [1, 0, 2.0], "yaw": 0, "anchor": "object", "parent": "pic"}, | |
| {"id": "win", "category": "window", "size": [1, .1, 1.2], "pos": [3, 0, .9], "yaw": 0}]} | |
| s = scope_objects(room) | |
| assert [o["id"] for o in s["objects"]] == ["desk", "lamp", "sofa"], s | |
| assert s["objects"][1]["parent"] == "desk" and s["objects"][1]["anchor"] == "object" | |
| a = {o["id"]: o["anchor"] for o in infer_anchors({**room, "objects": [dict(o) for o in room["objects"]]})["objects"]} | |
| assert a["pic"] == "wall" and a["cl"] == "ceiling" and a["art"] == "wall", a # art above a sofa is not "on" it | |
| assert is_structure("window") and is_structure("door(screen door, screen)") and not is_structure("floor lamp") | |
| for c in ("wall", "floor", "Wall design", "ceiling combination", "floor mold", "otherstructure", "room_partition", | |
| "radiator", "support_column", "vertical core stair 1", "door(screen door, screen)"): | |
| assert is_structure(c), c | |
| for c in ("plant_floor", "floor_plant_large", "locker_column", "floor_bookshelf", "bookshelf_wall_unit", | |
| "floor-standing air purifier", "wall_hung_toilet", "floor lamp", "wall_cabinet", "ceiling fan", "wall_mirror"): | |
| assert not is_structure(c), c | |
| sofa = {"id": "s", "category": "sofa", "size": [2, .9, .8], "pos": [1, 1, 0.07], "yaw": 0} | |
| rug = {"id": "r", "category": "rug", "size": [3, 2, .02], "pos": [1, 1, 0], "yaw": 0} | |
| got = {o["id"]: (o["anchor"], o.get("parent")) for o in infer_anchors({"objects": [dict(sofa), dict(rug)]})["objects"]} | |
| assert got == {"s": ("floor", None), "r": ("floor", None)}, got # 7 cm up = standing, not on the rug | |
| fx = {"boundary": [[0, 0], [5, 0], [5, 4], [0, 4]], "objects": [ | |
| {"id": "d", "category": "door", "size": [.9, .1, 2.1], "pos": [2, 0, 0], "yaw": 0}, | |
| {"id": "w", "category": "window", "size": [1.2, .1, 1.3], "pos": [4.98, 2, .9], "yaw": math.pi / 2}, | |
| {"id": "c", "category": "support_column", "size": [.3, .3, 2.8], "pos": [2.5, 2, 0], "yaw": 0, "structure": True}, | |
| {"id": "b", "category": "beam", "size": [5, .3, .3], "pos": [2.5, 2, 2.5], "yaw": 0}, | |
| {"id": "f", "category": "floor", "size": [5, 4, .02], "pos": [2.5, 2, 0], "yaw": 0}, | |
| {"id": "k", "category": "curtain", "size": [1.5, .1, 2.4], "pos": [4.95, 2, 0], "yaw": 0}, | |
| {"id": "s", "category": "socket", "size": [.08, .02, .08], "pos": [1, 0.01, .3], "yaw": 0}, | |
| {"id": "w1", "category": "wall", "size": [4, .1, 2.8], "pos": [2.5, 0.05, 0], "yaw": 0}, | |
| {"id": "w2", "category": "wall", "size": [2, .1, 2.8], "pos": [2.5, 2, 0], "yaw": 0}, | |
| {"id": "p", "category": "wall panels", "size": [3, .05, 2.8], "pos": [1.5, 0.02, 0], "yaw": 0}, | |
| {"id": "sc", "category": "window screening", "size": [1.5, .05, 2.4], "pos": [2, 3.98, 0], "yaw": 0}, | |
| {"id": "t", "category": "table", "size": [1.2, .6, .75], "pos": [1, 1, 0], "yaw": 0}]} | |
| assert [o["id"] for o in fixed_geometry(fx)] == ["d", "w", "c", "w2"], fixed_geometry(fx) | |
| assert [o["id"] for o in fixed_geometry({**fx, "boundary_type": "hull"})] == ["d", "w", "c"] # hull: walls are not partitions | |
| assert not is_structure("step ladder") and is_structure("styling column") and is_structure("otherstructure") | |
| assert is_structure("elevator shaft") and is_structure("banister") and not is_structure("floor lamp") | |
| assert not is_structure("elevator_lobby_bench") and is_structure("stair_railing") and is_structure("bedroom_door") | |
| panel = {"boundary": fx["boundary"], "objects": [{"id": "pp", "category": "low_partition_panel", "size": [.3, 1, 1.7], | |
| "pos": [2.5, 2, 0], "yaw": 0}, {"id": "wp", "category": "wall panels", | |
| "size": [3, .05, 2.8], "pos": [1.5, 0.02, 0], "yaw": 0}]} | |
| assert [o["id"] for o in fixed_geometry(panel)] == ["pp"] # a partition panel is fixed, a wall panel is not | |
| # a frame standing on a dresser is on it; a wall-hung cabinet floats -> fixed in a polygon room, floor in a hull | |
| dr = {"id": "dr", "category": "dresser", "size": [1, .5, .8], "pos": [1, 1, 0], "yaw": 0} | |
| fr = {"id": "fr", "category": "picture frame", "size": [.2, .05, .25], "pos": [1, 1, .8], "yaw": 0} | |
| cb = {"id": "cb", "category": "bathroom cabinet", "size": [.6, .4, .5], "pos": [3, 3, .35], "yaw": 0} | |
| bd = {"id": "bd", "category": "bed", "size": [2, 1.6, .5], "pos": [3, 1, .35], "yaw": 0} | |
| got = {o["id"]: (o["anchor"], o.get("parent")) for o in annotate({"boundary_type": "polygon", "objects": [dr, fr, cb, bd]})} | |
| assert got == {"dr": ("floor", None), "fr": ("object", "dr"), "cb": ("fixed", None), "bd": ("floor", None)}, got | |
| got = {o["id"]: o["anchor"] for o in annotate({"boundary_type": "hull", "objects": [dict(cb)]})} | |
| assert got == {"cb": "floor"}, got | |
| assert annotate({"source": "Scan2CAD", "boundary_type": "polygon", "objects": [dict(cb)]})[0]["anchor"] == "floor" | |
| strip = {"id": "ps", "category": "power_outlet_strip", "size": [.3, .06, .04], "pos": [1, 1, .8], "yaw": 0, | |
| "anchor": "object", "parent": "dr"} | |
| assert [o["id"] for o in annotate({"objects": [dict(dr), strip]})] == ["dr", "ps"] and not fixed_geometry( | |
| {"boundary": fx["boundary"], "objects": [dict(dr), strip]}) | |
| print("anchors.py self-check ok") | |