Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- program new;
- {$DEFINE SRL_USE_REMOTEINPUT}
- {$I SRL/osr.simba}
- (*
- This solution assumes that you have an anchor that is either perpendicular or parallel to the door
- (it's either in the angle of facing the closed door, or it's facing the open door)
- //
- //|
- //||
- //_||______
- //| __ __ |
- ##| | || | |
- ##| | || | | _
- ##| |__||__| | (_)
- ##| __ __()| Parallel example <--|-->
- ##| | || | | <-- Door --- Anchor --> _ | _
- ##| | || | | `\__/ \__/`
- ##| | || | | `-. .-´
- ##| |__||__| | '
- ##|__________|
- //
- Concept:
- Find the door and find some object which we call anchor, in this example I'm using a black ledger.
- Now we can use the distance from the ledger to the door to determine if the door is open.
- The door state can be defined as
- If the distance between Door and Anchor is less than a set value, the state of the door is
- > Open if: The anchor is parallel to the closed door (parallel meaning to the direction you enter)
- > Closed if: The anchor is perpendicular to the closed door (reverse)
- Written example, assuming the anchor's location is parallel to the direction you enter through the door.
- An open door could have a distance between 18..19,
- while a closed door could have a distance between 21..22.
- We can therefor state the cutoff / middle between the two states as approximately 20.
- How you choose to attack it is up to you. So long as you can generate varying distance-value
- between states to something else (an anchor), you can use this concept.
- *)
- {$DEFINE DOOR_DEBUG_DISTANCE}
- type
- EDoorState = (dsUndefined, dsOpen, dsClosed);
- var
- RSW: TRSWalker;
- (*
- Input:
- Door: The TPA of the door
- Anchor: The TPA of the Anchor
- Split: This is the cutoffpoint between a closed and an open door
- Inverse: If the door is not parallel then this should be True (auto False)
- UseMean: Mean may give less accurate distance value, so it may result in (more) false-positives
- But it may be less prone to noisy pixels from color-finding.
- Return `dsOpen` if the door is open based on given input data
- if the method fails it will return `dsUndefined`, otherwise dsFalse; `ds` is short for doorstate
- *)
- function IsDoorOpen(Door, Anchor: TPointArray; Split: Double; Inverse: Boolean = False; UseMean: Boolean = False): EDoorState;
- var
- p,q: Vector3;
- me,ptAnchor,ptDoor: TPoint;
- ATPA: T2DPointArray;
- begin
- // ensure no failure
- if (Length(Anchor) = 0) or (length(Door) = 0) then Exit(dsUndefined);
- // find the point in the ledger that's closest to the door and vice versa
- // alternatively we could just use the mean and skip this step in many cases.
- if not UseMean then begin
- anchor.Sort(door.Mean());
- ptAnchor := anchor[0];
- door.Sort(ptAnchor);
- ptDoor := door[0];
- end else begin
- ptAnchor := anchor.Mean();
- ptDoor := door.Mean();
- end;
- // convert to minimap to work in 2d space, so distance is always the same no matter position,
- // camera angle and zoom.
- p := MainScreen.PointToMM(ptDoor);
- q := MainScreen.PointToMM(ptAnchor);
- {$IFDEF DOOR_DEBUG_DISTANCE}
- // write the distance output for debugging
- // this is to get the distance (number) between the anchor and door (in both states, open and closed)
- WriteLn p.Distance(q);
- {$ENDIF}
- if (p.Distance(q) <= Split) xor inverse then
- Exit(dsOpen)
- else
- Exit(dsClosed);
- end;
- (*
- You can use your own methods to find doors and anchors. This is just as an example.
- *)
- procedure FindDoorAndAnchor(WorldPos: TPoint; out Door, Anchor: TPointArray);
- var
- ledger: TPointArray;
- ATPA: T2DPointArray;
- AnchorSearchBox, DoorSearchBox: TBox;
- begin
- // rough area of where the anchor and door is (world map coordinates)
- AnchorSearchBox := RSW.GetTileMSEx(WorldPos, [2656, 2734]).Expand(10).Bounds();
- DoorSearchBox := RSW.GetTileMSEx(WorldPos, [2646, 2754]).Expand(30).Bounds();
- DoorSearchBox.LimitTo(MainScreen.Bounds);
- AnchorSearchBox.LimitTo(MainScreen.Bounds);
- // find the anchor, and the door tpas (regular color-data from ACA)
- srl.FindColors(anchor, CTS2(1776416, 1, 0.01, 0.01), AnchorSearchBox);
- srl.FindColors(door, CTS2(1993096, 13, 0.08, 1.02), DoorSearchBox);
- // basic noise filtering
- ATPA := door.Erode(1).Grow(1).Cluster(2);
- door := ATPA.Biggest();
- // basic noise filtering, small object, so I dont erode noise.
- ATPA := anchor.Cluster(2);
- anchor := ATPA.Biggest();
- end;
- (*
- Test run:
- *)
- var
- door,anchor: TPointArray;
- begin
- RSW.Setup([[2656-500, 2734-500, 2656+500, 2734+500]]);
- RSClient.Image.SetFontSize(15);
- RSClient.Image.SetFontAntialiasing(False);
- WriteLn RSW.GetMyPos();
- while True do
- begin
- MM2MS.ZoomLevel := Options.GetZoomLevel();
- FindDoorAndAnchor(RSW.GetMyPos(), door, anchor);
- RSClient.Image.Clear();
- case IsDoorOpen(Door, Anchor, 19.4, False, False) of
- dsUndefined: ;
- dsOpen: RSClient.Image.DrawText('Open', Door.Mean(), 1);
- dsClosed: RSClient.Image.DrawText('Closed', Door.Mean(), 1);
- end;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement