|
Antwort |
Registriert seit: 22. Okt 2012 267 Beiträge |
#1
Hallo,
ich habe die Tage etwas mit Augmented Reality gespielt und für ein Softwareprojekt einlesen. Im Netz gibt es mehrere gute Quellen die auch recht anschaulich das Problem erklären. Nachdem ich folgendes Tutorial gelesen habe, entstand in knapp einer Stunde unten liegender Code (auf Basis der dort erklärten Bibliotheken): http://www.raywenderlich.com/42266/a...location-based Ich bin mir sicher das der Code zu UpdateLocations nicht ganz korrekt ist (da im Original mit UIViews gearbeitet wird und ich versucht habe das ganze so abstrakt wie möglich zu halten). Ebenso würde mich wundern, wenn mein Transformationscode korrekt ist. Der entstand "On the fly" und naja die letzte Mathevorlesung ist schon *hüstel* 12 Jahre her, auch ist Objective C nicht meine Stärke Eventuell juckt es ja den ein oder anderen damit etwas sinnvolles zu erstellen bzw. mit mir die Fehler zu beheben? Zumindest würde es mich freuen.
Delphi-Quellcode:
(*
Augmented Reality Toolkit for Delphi based on the iPhone Augmented Reality Toolkit Copyright (c) 2013 Agilite Software Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit UARKit; interface uses Classes, SysUtils; const ADJUST_BY = 30; SCALE_FACTOR = 1.0; DEGREE_TO_UPDATE = 1; HEADING_NOT_SET = -1.0; type TARCameraOrientation = ( coLandscapeLeft, coLandscapeRight, coPortrait, coPortraitUpsideDown); TARList = TList; TARPoint = record x, y: single; end; TARRect = record Left, Top, Right, Bottom: single; end; TARLocation = record Latitude, Longitude, Altitude: single; end; TARVector = record x, y, z: single; end; TARMatrix = record m11, m12, m13, m14: single; m21, m22, m23, m24: single; m31, m32, m33, m34: single; m41, m42, m43, m44: single; end; const ARIdentityMatrix: TARMatrix = ( m11: 1; m12: 0; m13: 0; m14: 0; m21: 0; m22: 1; m23: 0; m24: 0; m31: 0; m32: 0; m33: 1; m34: 0; m41: 0; m42: 0; m43: 0; m44: 1); type TARCoordinate = class private FTitle: string; FSubtitle: string; FAzimuth: single; FInclination: single; FRadialDistance: single; public constructor Create(const ARadialDistance, AInclination, AAzimuth: single); property Azimuth: single read FAzimuth write FAzimuth; property Inclination: single read FInclination write FInclination; property RadialDistance: single read FRadialDistance write FRadialDistance; property Title: string read FTitle write FTitle; property Subtitle: string read FSubtitle write FSubtitle; end; TARGeoCoordinate = class(TARCoordinate) private FDisplayView: TARRect; FGeoLocation: TARLocation; FDistanceFromOrigin: single; FWidth: integer; FHeight: integer; function AngleFromCoordinate(const first, second: TARLocation): single; public constructor Create(const ALocation: TARLocation; const ATitle: string); overload; constructor Create(const AOrigin: TARGeoCoordinate); overload; procedure CalibrateUsingOrigin(const AOrigin: TARLocation); property Width: integer read FWidth write FWidth; property Height: integer read FHeight write FHeight; property DisplayView: TARRect read FDisplayView write FDisplayView; property GeoLocation: TARLocation read FGeoLocation; property DistanceFromOrigin: Single read FDistanceFromOrigin; end; TARController = class private FLatestHeading: single; FDegreeRange: single; FViewAngle: single; FPrevHeading: single; FDisplayView: TARRect; FCoordinates: TARList; FCameraOrientation: TARCameraOrientation; FCenterCoordinate: TARCoordinate; FCenterLocation: TARLocation; FMaximumScaleDistance: single; FMinimumScaleFactor: single; FMaximumRotationAngle: single; FScaleViewsBasedOnDistance: Boolean; FRotateViewsBasedOnPerspective: Boolean; procedure UpdateLocations(); function FindDeltaOfRadianCenter(centerAzimuth, pointAzimuth: single; var isBetweenNorth: Boolean): single; function PointForCoordinate(const coord: TARcoordinate): TARPoint; function ShouldDisplayCoordinate(const coord: TARCoordinate): Boolean; procedure SetCenterLocation(const ALocation: TARLocation); procedure SetDisplayView(const ADisplayView: TARRect); procedure SetScaleData(const index: integer; const AValue: Single); procedure SetViewData(const index: integer; const AValue: Boolean); public constructor Create(const ADisplayView: TARRect); destructor Destroy; override; procedure Clear; procedure Add(const coordinate: TARCoordinate); procedure Remove(const coordinate: TARCoordinate); procedure UpdateAccelerometer(const Ax, Ay, Az: single); procedure UpdateHeading(const AHeading: single); property CenterLocation: TARLocation read FCenterLocation write SetCenterLocation; property DisplayView: TARRect read FDisplayView write SetDisplayView; property MaximumScaleDistance: single index 0 read FMaximumScaleDistance write SetScaleData; property MinimumScaleFactor: single index 1 read FMinimumScaleFactor write SetScaleData; property MaximumRotationAngle: single index 2 read FMaximumRotationAngle write SetScaleData; property ScaleViewsBasedOnDistance: Boolean index 0 read FScaleViewsBasedOnDistance write SetViewData; property RotateViewsBasedOnPerspective: Boolean index 1 read FRotateViewsBasedOnPerspective write SetViewData; end; implementation uses Math; function ToDeg(const x: single): single; begin result := PI * x / 180.0; end; function toRad(const x: single): single; begin result := x * 180.0 / PI; end; function ARTransform3DScale(const Matrix: TARMatrix; const ScaleX, ScaleY, ScaleZ: single): TARMatrix; begin result := Matrix; result.m11 := ScaleX; result.m22 := ScaleY; result.m33 := ScaleZ; result.m44 := 1; end; function ARRectWidth(const R: TARRect): Single; begin result := R.Right - R.Left; end; function ARRectHeight(const R: TARRect): Single; begin result := R.Bottom - R.Top; end; function ARVector(const x, y, z: single): TARVector; begin result.x := x; result.y := y; result.z := z; end; function ARSetTransform(const src: TARVector; const m: TARMatrix): TARVector; var w: single; begin result.x := src.x * m.m11 + src.y * m.m21 + src.z * m.m31 + m.m41; result.y := src.x * m.m12 + src.y * m.m22 + src.z * m.m31 + m.m41; result.z := src.x * m.m13 + src.y * m.m23 + src.z * m.m32 + m.m41; w := src.x * m.m14 + src.y * m.m24 + src.z * m.m34 + m.m44; if (w <> 1) and (w <> 0) then begin result.x := result.x / w; result.y := result.y / w; result.z := result.z / w; end; end; procedure SetTransform(var Rect: TARRect; const Matrix: TARMatrix); var v1, v2: TARVector; begin v1 := ARSetTransform(ArVector(Rect.Left, Rect.Top, 0), Matrix); v2 := ARSetTransform(ArVector(Rect.Right, Rect.Bottom, 0), Matrix); Rect.Left := v1.x; Rect.Top := v1.y; Rect.Right := v2.x; Rect.Bottom := v2.y; end; function DistanceFromLocation(const Location1, Location2: TARLocation): single; // http://www.movable-type.co.uk/scripts/latlong.html var lat1, lat2, lon1, lon2: single; Haversine, dLat, dLon: single; begin lat1 := ToDeg(Location1.Latitude); lon1 := ToDeg(Location1.Longitude); lat2 := ToDeg(Location2.Latitude); lon2 := ToDeg(Location2.Longitude); dLat := (lat2 - lat1); dLon := (lon2 - lon1); Haversine := sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(lat2); result := 6371 * (2 * arctan2(sqrt(Haversine), sqrt(1 - Haversine))); end; { TARCoordinate } constructor TARCoordinate.create(const ARadialDistance, AInclination, AAzimuth: single); begin FRadialDistance := ARadialDistance; FInclination := AInclination; FAzimuth := AAzimuth; FTitle := ''; FSubtitle := ''; end; { TARGeoCoordinate } function TARGeoCoordinate.angleFromCoordinate(const first, second: TARLocation): single; var longitudinalDifference, latitudinalDifference: single; possibleAzimuth: single; begin longitudinalDifference := second.longitude - first.longitude; latitudinalDifference := second.latitude - first.latitude; possibleAzimuth := (PI * 0.5) - arctan(latitudinalDifference / longitudinalDifference); if (longitudinalDifference > 0) then result := possibleAzimuth else if (longitudinalDifference < 0) then result := possibleAzimuth + PI else if (latitudinalDifference < 0) then result := PI else result := 0; end; constructor TARGeoCoordinate.create(const ALocation: TARLocation; const ATitle: string); begin inherited create(0, 0, 0); FGeoLocation := ALocation; FTitle := Title; end; constructor TARGeoCoordinate.create(const AOrigin: TARGeoCoordinate); begin inherited create(0, 0, 0); calibrateUsingOrigin(AOrigin.GeoLocation); FTitle := ''; end; procedure TARGeoCoordinate.calibrateUsingOrigin(const AOrigin: TARLocation); var angle: single; begin FDistanceFromOrigin := DistanceFromLocation(GeoLocation, AOrigin); RadialDistance := sqrt(power(AOrigin.Altitude - geoLocation.altitude, 2) + power(distanceFromOrigin, 2)); angle := sin(ABS(Aorigin.altitude - geoLocation.altitude) / radialDistance); if (Aorigin.altitude > geoLocation.altitude) then angle := -angle; Inclination := angle; Azimuth := angleFromCoordinate(AOrigin, geoLocation); end; { TARController } constructor TARController.create(const ADisplayView: TARRect); begin FCenterCoordinate := TARCoordinate.Create(1.0, 0, 0); FCoordinates := TARList.create; FLatestHeading := HEADING_NOT_SET; FPrevHeading := HEADING_NOT_SET; FMaximumScaleDistance := 0.0; FMinimumScaleFactor := SCALE_FACTOR; FScaleViewsBasedOnDistance := false; FRotateViewsBasedOnPerspective := false; FMaximumRotationAngle := PI / 6.0; FDisplayView := ADisplayView; FDegreeRange := ARRectWidth(ADisplayView) / ADJUST_BY; FCenterLocation.Latitude := 37.41711; FCenterLocation.longitude := -122.02528; end; destructor TARController.Destroy; begin Clear; FCoordinates.Free; FCenterCoordinate.free; inherited; end; procedure TARController.Clear; var i: integer; obj: TObject; begin for i := 0 to FCoordinates.count - 1 do begin obj := FCoordinates[i]; FreeAndNil(obj); end; FCoordinates.clear; end; procedure TARController.Add(const coordinate: TARCoordinate); begin FCoordinates.Add(Coordinate); end; procedure TARController.Remove(const coordinate: TARCoordinate); begin FCoordinates.Remove(coordinate) end; function TARController.findDeltaOfRadianCenter(centerAzimuth: single; pointAzimuth: single; var isBetweenNorth: Boolean): single; begin if centerAzimuth < 0.0 then centerAzimuth := 2 * PI + centerAzimuth; if centerAzimuth > 2 * PI then centerAzimuth := centerAzimuth - 2 * PI; result := abs(pointAzimuth - centerAzimuth); isBetweenNorth := false; // If values are on either side of the Azimuth of North we need to adjust it. Only check the degree range if (centerAzimuth < ToDeg(FDegreeRange)) and (pointAzimuth > ToDeg(360 - FDegreeRange)) then begin result := centerAzimuth + (2 * PI - pointAzimuth); isBetweenNorth := true; end else if (pointAzimuth < ToDeg(FDegreeRange)) and (centerAzimuth > ToDeg(360 - FDegreeRange)) then begin result := (pointAzimuth + (2 * PI - centerAzimuth)); isBetweenNorth := true; end; end; function TARController.shouldDisplayCoordinate(const coord: TARCoordinate): Boolean; var isBetweenNorth: Boolean; deltaAzimuth: single; begin deltaAzimuth := findDeltaOfRadianCenter(FcenterCoordinate.azimuth, coord.azimuth, isBetweenNorth); result := (deltaAzimuth <= ToDeg(FDegreeRange)); end; function TARController.pointForCoordinate(const coord: TARCoordinate): TARPoint; var isBetweenNorth: boolean; deltaAzimith: single; begin isBetweenNorth := false; deltaAzimith := findDeltaOfRadianCenter(FcenterCoordinate.azimuth, coord.azimuth, isBetweenNorth); if (((coord.azimuth > FcenterCoordinate.azimuth) and (not isBetweenNorth)) or ((FcenterCoordinate.azimuth > ToDeg(360 - FDegreeRange)) and (coord.azimuth < ToDeg(FDegreeRange)))) then result.x := (ARRectWidth(FDisplayView) / 2) + ((deltaAzimith / ToDeg(1)) * ADJUST_BY) // Right side of Azimuth else result.x := (ARRectWidth(FDisplayView) / 2) - ((deltaAzimith / ToDeg(1)) * ADJUST_BY); // Left side of Azimuth result.y := (ARRectHeight(FDisplayView) / 2) + (toRad(PI / 2.0 + FViewAngle) * 2.0); end; procedure TARController.SetCenterLocation(const ALocation: TARLocation); var i: integer; geoLocation: TARCoordinate; begin FcenterLocation := ALocation; for i := 0 to FCoordinates.Count - 1 do begin geoLocation := FCoordinates[i]; if geoLocation is TARGeoCoordinate then begin (geoLocation as TARGeoCoordinate).calibrateUsingOrigin(FCenterLocation); if (geoLocation.radialDistance > FMaximumScaleDistance) then FMaximumScaleDistance := geoLocation.radialDistance; end; end; end; procedure TARController.UpdateAccelerometer(const Ax, Ay, Az: single); begin case FCameraOrientation of coLandscapeLeft: FViewAngle := arctan2(Ax, Az); coLandscapeRight: FViewAngle := arctan2(-Ax, Az); coPortrait: FViewAngle := arctan2(Ay, Az); else FViewAngle := arctan2(-Ay, Az); end; end; procedure TARController.UpdateHeading(const AHeading: single); var adjustment: single; begin FLatestHeading := ToDeg(AHeading); //Let's only update the Center Coordinate when we have adjusted by more than X degrees if (abs(FLatestHeading - FPrevHeading) >= ToDeg(DEGREE_TO_UPDATE)) or (FPrevHeading = HEADING_NOT_SET) then begin FPrevHeading := FLatestHeading; case FCameraOrientation of coLandscapeLeft: adjustment := ToDeg(270); coLandscapeRight: adjustment := ToDeg(90); coPortraitUpsideDown: adjustment := ToDeg(180); else adjustment := 0; end; FCenterCoordinate.Azimuth := FLatestHeading - adjustment; UpdateLocations(); end; end; procedure TARController.SetViewData(const index: integer; const AValue: Boolean); begin case index of 0: FScaleViewsBasedOnDistance := AValue; 1: FRotateViewsBasedOnPerspective := AValue; end; UpdateLocations; end; procedure TARController.SetScaleData(const index: integer; const AValue: Single); begin case index of 0: FMaximumScaleDistance := AValue; 1: FMinimumScaleFactor := AValue; 2: FMaximumRotationAngle := AValue; end; UpdateLocations; end; procedure TARController.SetDisplayView(const ADisplayView: TARRect); begin FDisplayView := ADisplayView; UpdateLocations; end; procedure TARController.UpdateLocations; var i: integer; item: TARGeoCoordinate; loc: TARPoint; scaleFactor: single; transform: TARMatrix; R: TARRect; width, height: single; begin for i := 0 to FCoordinates.Count - 1 do begin item := FCoordinates[i]; if shouldDisplayCoordinate(item) then begin loc := pointForCoordinate(item); scaleFactor := SCALE_FACTOR; if (FScaleViewsBasedOnDistance) then scaleFactor := scaleFactor - (FMinimumScaleFactor * item.radialDistance) / FMaximumScaleDistance; width := item.width * scaleFactor; height := item.height * scaleFactor; R.Left := loc.x - width / 2.0; R.Top := loc.y; R.Right := R.Left + width; R.Bottom := R.Top + height; transform := ARIdentityMatrix; // Set the scale if it needs it. Scale the perspective transform if we have one. if FScaleViewsBasedOnDistance then transform := ARTransform3DScale(transform, scaleFactor, scaleFactor, scaleFactor); if FRotateViewsBasedOnPerspective then transform.m34 := 1.0 / 300.0; SetTransform(R, transform); item.DisplayView := R; end; end; end; end. Geändert von CHackbart (16. Dez 2013 um 12:49 Uhr) |
Zitat |
Registriert seit: 11. Aug 2007 357 Beiträge |
#2
Ui,
toDeg und toRad sind in der Funktionsweise umgedreht, das war sicher nur nen Typo - im Code passt das ganze aber. Ansonsten scheint es zu gehen - zumindest scheint meine Testanwendung die Daten und die Entfernung der manuell eingegebenen POIs darzustellen. Was fehlt ist die Elevation/Inclinationsdarstellung. Da müsste man bei der Punktberechnung neben dem Betrachtungswinkel noch den Wert mit einbeziehen. Wobei ich mir sicher bin das da kein result.y := (FHeight / 2) + (toDeg(PI / 2.0 + FViewAngle-Coord.inclination)) * 2.0; ausreicht. Nur mal als Überlegeung, der nimmt die Bildmitte als Horizont und addiert 2*(90°-Betrachgungswinkel-Inklination) das ist sicher Usus Hat jemand eine Idee, ansonsten ist das scheinbar fast alles korrekt. Ich hab nur die TList nach außen geführt und ein paar Kleinigkeiten repariert (siehe oben, bzw. irgendwelche offensichtlichen Typos). |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |