Pessoal,
Só God sabe o quanto eu estou apanhando pra fazer isso.
O projeto é o seguinte:
- Funcionário tira foto(s) a partir de um celular, de um Local(Uma obra por exemplo)
- A foto é salva em bytes na tabela ApontamentoFoto
- Para mostrar a foto no google earth é preciso de: Latitude da foto + Longitude da foto + a foto em questão para cada Lat e Long
Ao estudar KML http://code.google.com/apis/ajax/playground/#html_string_balloons percebi que para colocar uma foto no earth e customiza-la é preciso que seja dentro de Ballon, junto com html, como vcs verão no código de KMLGenerator()…
O problema é que eu não tenho idéia de como fazer para mostrar essa foto junto com o kml no Google Earth, se eu levo o kml em um array de bytes para o earth eu nao tenho como parsear o kml na jsp pois estará em array de bytes, cara isso aqui para o meu conhecimento é osso…
Vejam o que vcs entenderam e opinem no que puderem, lembrando que o objetivo é criar vários pontos de marcação (Placemarks) no Google Earth,
contendo dentro de cada um deles(Lat e Long) uma foto…
Abrcs
Se eu explicar muito vou me complicar todo, o melhor é que vejam o código por favor e acompanhem os comentários a partir dos números:
google_earth.jsp
[code]var ge;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
// Fly to the Pentagon
var la = ge.createLookAt('');
la.set(37.42228990140251, -122.0822035425683, 50,
ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 45, 900);
ge.getView().setAbstractView(la);
// add a navigation control
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
// add some layers
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_TERRAIN, false);
/*
2 - Por exemplo aqui eu pegaria uma action que retornaria em bytes o kml la da classe KMLGenerator()
var urlAction = document.getElementById(“kmlFoto”);
alert(urlAction);
aqui faria o parse para o earth, mas obvio que não funcionou pois esta em bytes ao invés de uma String, essa é minha dúvida como trazer uma foto em bytes dentro de um StringBuffer como vcs verão na classe KMLGenerator().
ge.parseKml(urlAction);
ge.getFeatures().appendChild(); */
/* exibeFotos(ge); */
}
/*
1 - Essa função dwr trazia um kml gerado da classe KMLGenerator, porém
eu tenho que trazer por uma action. Veja que eu tenho que fazer um parse do kml
retornado para que o Earth o veja. Agora como fazer isso a partir da action?
function exibeFotos(ge) {
PainelEarthAjax.geraFotosObra(${obra.id},{
callback : function(kmlString) {
alert(kmlString);
var kmlObject = ge.parseKml(kmlString);
ge.getFeatures().appendChild(kmlObject);
}
});
return null;
} */
function failureCB(errorCode) {
}
/*
Essa é uma função hardcoded de exemplo que cria um placemark no kml
function createPlacemark() {
var placemark = ge.createPlacemark(’’);
placemark.setName(“placemark”);
ge.getFeatures().appendChild(placemark);
// Create style map for placemark
var icon = ge.createIcon('');
icon.setHref('http://maps.google.com/mapfiles/kml/paddle/red-circle.png');
var style = ge.createStyle('');
style.getIconStyle().setIcon(icon);
placemark.setStyleSelector(style);
// Create point
var la = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
var point = ge.createPoint('');
point.setLatitude(la.getLatitude());
point.setLongitude(la.getLongitude());
placemark.setGeometry(point);
} */
google.setOnLoadCallback(init);
PainelEarthAction
@Namespace(value = "/Consulta/Earth")
@ResultPath(value = "/")
@ParentPackage(value = "default")
public class PainelEarthAction extends BasicAction {
@Autowired
private LocalBusiness localBusiness;
private InputStream imageStream;
private String fileName;
private int idLocal = 1;
// outros atributos
@Action(value = "mostrarEarth", results = {
@Result(name = SUCCESS,
type="stream", params = {"contentType","image/jpeg",
"contentDisposition","attachment;filename='${fileName}'",
"inputName","imageStream", "bufferSize", "1024"})})
public String foto () {
try {
// busca um local pelo id
List<Local> locais = localBusiness.getLocalLatLong(new Local(idLocal));
// abaixo eu estou retornando todo o kml em Array de Bytes para que possa ir para a jsp, esse é o procedimento normal se fosse só a foto,
// mas eu não tenho só a foto, o ideal seria uma String com a foto la dentro, mas como a foto estaria em bytes dentro de uma String?
imageStream = KMLGenerator.getKmlAsStream(locais);
fileName = System.currentTimeMillis()+"_"+".jpg";
} catch (Exception e) { }
return SUCCESS;
}
// outros gets and sets
KMLGenerator()
public class KMLGenerator {
public static InputStream getKmlAsStream (List<Local> localFotos) {
return new ByteArrayInputStream(getKMLFromObra(localFotos).getBytes());
}
/**
* Método que cria o kml a partir dos valores obtidos na entidade local
* @param obraFotos
* Uma lista do objeto com os seus respectivos valores
* @return
* Uma String contendo o kml criado
*/
public static String getKMLFromObra (List<Local> localFotos) {
StringBuffer sb = new StringBuffer();
sb.append("<?xml version='1.0' encoding='UTF-8'?>");
sb.append("<kml xmlns='http://www.opengis.net/kml/2.2' " +
"xmlns:gx='http://www.google.com/kml/ext/2.2' " +
"xmlns:kml='http://www.opengis.net/kml/2.2' " +
"xmlns:atom='http://www.w3.org/2005/Atom'> ");
if (localFotos != null && localFotos.size() > 0) {
for (Local local : localFotos) {
for (ApontamentoFoto apontFoto : local.getApontamentoFoto()) {
sb.append("<Document>");
sb.append("<name>" + local.getDescricao() + "</name>");
/**
* Style
*/
sb.append("<Style id='defaultStyles'>");
// // icon
sb.append("<IconStyle>");
sb.append("<scale>1.1</scale>");
sb.append("<Icon>");
sb.append("<href>" + "http://localhost:8080/ConstruMobilFoto/lib/img/fotoIcon.png" + "</href>");
sb.append("</Icon>");
sb.append("</IconStyle>");
// // ballon Style
sb.append("<BalloonStyle>");
// // a background color for the balloon
sb.append("<bgColor>#F0F0F0</bgColor>");
// // styling of the balloon text
sb.append("<text><![CDATA[");
sb.append("<b><font color='#404040' size='+3'>Fotos Local</font></b>");
sb.append("<br/><br/>");
// aqui está o problema, para colocar uma foto teria que misturar kml junto com html, mas se eu fizer do jeito que esta ai ele retorna a foto
// em bytes, é claro ela foi salva em bytes. Agora como eu passaria tudo isso por parametro por uma action, eu fiz do jeito que esta lá na action
// mesmo, tentei tbm com dwr e não deu certo, mas o que eu preciso é por action e não dwr???
sb.append("<font face='Courier'><img alt='foto' src=' " + apontFoto.getFoto() + " ' /></font>");
sb.append("<br/><br/>");
sb.append("<p>aqui vão as fotos!</p>");
sb.append("<br/><br/>");
// // insert the to/from hyperlinks
sb.append("$[geDirections]");
sb.append("]]></text>");
sb.append("</BalloonStyle>");
sb.append("</Style>");
/**
* Placemark
*/
sb.append("<Placemark>");
sb.append("<name>" + "Local" + "</name>");
sb.append("<styleUrl>" + "#defaultStyles"+ "</styleUrl>");
sb.append("<altitudeMode>" + "relativeToGround" + "</altitudeMode>");
sb.append("<Point>");
sb.append("<altitudeMode>relativeToGround</altitudeMode>");
sb.append("<coordinates>" + apontFoto.getLongitude() + "," + apontFoto.getLatitude() + "," + 50 + "</coordinates>");
sb.append("</Point>");
sb.append("</Placemark>");
sb.append("</Document>");
sb.append("</kml>");
}
}
return sb.toString();
}
return null;
}
}
Assim que o cara loga no sistema a action é invocada em home.jsp, porém eu tenho outra opção no menu para que o cliente possa visualizar a action,
que é essa que estamos fazendo…
[code]
<div id="topo">
<s:include value="/WEB-INF/portal/include/topo.jsp" />
</div>
<div id="earth">
<s:div value="/Consulta/Earth/mostrarEarth.action">
<s:include value="/WEB-INF/portal/include/google_earth.jsp" />
<s:action name="mostrarEarth" namespace="/Consulta/Earth" executeResult="true" />
</s:div>
</div>
<div class="linha" style="margin-top:40px;position:absolute;bottom:80px;">
<s:include value="/WEB-INF/portal/include/rodape.jsp" />
</div>
[/code]